Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
64b0a02
remove wchar.h include from mimalloc.h (see also issue leanprover/lea…
daanx May 4, 2026
a0212e2
fix(osx): implement introspect.reinit_lock to avoid fork() crash
leiyue123 Jun 15, 2026
d63ab62
update _mi_prim_getenv interface to distinguish not-found and errors …
daanx Jun 22, 2026
4d258d7
Merge branch 'dev' into dev2
daanx Jun 22, 2026
4f7d2fe
Merge pull request #1315 from leiyue123/fix/osx-reinit-lock-dev
daanx Jun 22, 2026
53fa5cc
Merge branch 'dev' into dev2
daanx Jun 22, 2026
dc34dce
fix typo, pr #1308
daanx Jun 22, 2026
79c1f75
backport PR #1293
daanx Jun 22, 2026
7b5f598
Merge branch 'dev' into dev2
daanx Jun 22, 2026
0f3d716
apply PR #1294
daanx Jun 22, 2026
569be66
apply PR #1298 (by @cppcoffee)
daanx Jun 22, 2026
e8e1e77
add riscv64 TLS support
mengzhuo Jun 5, 2026
021bc3a
add riscv64 atomic yield (pause with Zihintpause fallback)
mengzhuo Jun 5, 2026
580c503
only use delayed_free_all on abandonment, but otherwise prefer delaye…
daanx Jun 23, 2026
9285427
add backoff to atomic_yield with sleep(0) calls, see also issue #1317
daanx Jun 23, 2026
4a32f40
Merge branch 'dev' into dev2
daanx Jun 23, 2026
84243a7
fix format specifier for memid (pr #1321)
daanx Jul 7, 2026
f5b637a
apply format specifier fix (pr #1321 by @StanFromIreland)
daanx Jul 7, 2026
4925229
Merge pull request #1319 from mengzhuo/riscv64
daanx Jul 7, 2026
414c8c4
fix missing parenthesis (pr #1319)
daanx Jul 7, 2026
aed99d3
Advise MADV_HUGEPAGE independently of allow_large
rui314 Jul 9, 2026
acea8bc
improve _mi_strnlen, issue #1271, issue 27
daanx Jul 13, 2026
3e21fef
check error on clock_gettime, #1271 issue 15
daanx Jul 13, 2026
cafd351
check error on clock_gettime for Wasi, #1271 issue 15
daanx Jul 13, 2026
60173ff
check error on clock_gettime for Wasi and unix, #1271 issue 15
daanx Jul 13, 2026
f4a927b
adjust mi_good_size for potential padding size, #1271, issue 18
daanx Jul 13, 2026
2caaefd
fix missing semi-colon, issue #1271, issue 31
daanx Jul 13, 2026
885c408
check pthread key creation for error, issue #1271, issue 13
daanx Jul 14, 2026
c4c3f75
use atomic for huge 1Gib page available flag, issue #1271, issue 14
daanx Jul 14, 2026
27037df
ensure process_done only runs once, #1271 issue 12
daanx Jul 14, 2026
2a7ee74
merge from dev
daanx Jul 14, 2026
93ec401
update macos zone management to reflect dev3 changes
daanx Jul 14, 2026
0f13804
disable dynamic override test in C++ on macos (for dev and dev2)
daanx Jul 14, 2026
678baa9
Merge branch 'dev' into dev2
daanx Jul 14, 2026
82c1688
limit size for hint address only in secure mode, issue #1290
daanx Jul 14, 2026
a35ed8a
Merge branch 'dev' into dev2
daanx Jul 14, 2026
0748322
remove mi_attr_no_except from mi_posix_memalign (issue #794)
daanx Jul 14, 2026
6d4e8dc
bump version to v1.9.11
daanx Jul 14, 2026
37ae20e
bump release version to v3.4.0
daanx Jul 14, 2026
16e6a1e
bump version to v2.4.0
daanx Jul 14, 2026
ff11fa7
update readme
daanx Jul 14, 2026
26b6bb5
Merge branch 'dev' into dev2
daanx Jul 14, 2026
a894366
Merge branch 'dev2' into dev-main
daanx Jul 14, 2026
9cfe804
Merge pull request #1328 from rui314/thp-advise-huge
daanx Jul 14, 2026
72b3fb2
update readme
daanx Jul 15, 2026
a0a0c90
Merge branch 'dev' into dev2
daanx Jul 15, 2026
e39ada5
bump version to v2.4.1
daanx Jul 15, 2026
e8e8306
prepare release 3.4.1
daanx Jul 15, 2026
30ac9d5
Merge branch 'dev' into dev2
daanx Jul 15, 2026
b7642b8
Merge branch 'dev2' into dev-main
daanx Jul 15, 2026
578da01
update to softprops/action-gh-release v3
daanx Jul 15, 2026
da57b11
Merge branch 'dev' into dev2
daanx Jul 15, 2026
032209d
Merge branch 'dev2' into dev-main
daanx Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permissions:
contents: write

env:
RELEASE: Release v3.3.2
RELEASE: Release v3.4.1
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

name: Release
Expand All @@ -19,7 +19,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
branch: [v1.9.10,v2.3.2,v3.3.2] # [dev,dev2,dev3]
branch: [v1.9.11,v2.4.1,v3.4.1] # [dev,dev2,dev3]
# we build on the oldest ubuntu version for better binary compatibility.
os: [windows-latest, macOS-latest, macos-15-intel, ubuntu-22.04, ubuntu-22.04-arm]

Expand All @@ -45,7 +45,7 @@ jobs:

# Create a release: https://github.com/softprops/action-gh-release (MIT license)
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: ${{ env.RELEASE != '' && env.RELEASE != 'no' }}
with:
name: ${{ env.RELEASE }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
ctest --test-dir out/debug-cxx --verbose --timeout 240 -C Debug

- name: Release, C++
if: matrix.tests == 'basic' && runner.os == 'Linux' # windows already uses C++ by default; macOS interpose does not work well with C++
if: matrix.tests == 'basic' && runner.os != 'Windows' # windows already uses C++ by default
run: |
cmake . -B out/release-cxx -DCMAKE_BUILD_TYPE=Release -DMI_OPT_ARCH=ON -DMI_USE_CXX=ON
cmake --build out/release-cxx --parallel 8 --config Release
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ endif()
if(MI_USE_CXX)
message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)")
set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX )
set_source_files_properties(src/static.c test/test-api.c test/test-api-fill test/test-stress PROPERTIES LANGUAGE CXX )
set_source_files_properties(src/static.c test/test-api.c test/test-api-fill.c test/test-stress.c PROPERTIES LANGUAGE CXX )
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang|Clang")
list(APPEND mi_cflags -Wno-deprecated)
endif()
Expand Down Expand Up @@ -762,7 +762,7 @@ if (MI_BUILD_TESTS)
endforeach()

# dynamic override test
if(MI_BUILD_SHARED AND NOT (MI_TRACK_ASAN OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
if(MI_BUILD_SHARED AND NOT (MI_TRACK_ASAN OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN) AND NOT (APPLE AND MI_USE_CXX))
add_executable(mimalloc-test-stress-dynamic test/test-stress.c)
target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags})
Expand Down
14 changes: 9 additions & 5 deletions bin/bundle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ warn() {
}

stop() {
warn $@
warn "$@"
exit 1
}

Expand Down Expand Up @@ -103,7 +103,11 @@ process_options() {
-p) shift
PREFIX="$1";;
-p=*|--prefix=*)
PREFIX=`eval echo $flag_arg`;; # no quotes so ~ gets expanded (issue #412)
case "$flag_arg" in
"~") PREFIX="$HOME" ;;
"~/"*) PREFIX="$HOME/${flag_arg#~/}" ;;
*) PREFIX="$flag_arg" ;;
esac;;
-h|--help|-\?|help|\?)
MODE="help";;
*) case "$flag" in
Expand Down Expand Up @@ -139,7 +143,7 @@ download_file() { # <url|file> <destination file>
fi;;
*)
info "Copying: $1"
if ! cp $1 $2 ; then
if ! cp "$1" "$2" ; then
stop "Unable to copy from $1"
fi;;
esac
Expand Down Expand Up @@ -220,7 +224,7 @@ main_help() {
main_start() {
detect_osarch
detect_git_tag
process_options $@
process_options "$@"
if [ "$MODE" = "help" ] ; then
main_help
else
Expand All @@ -229,4 +233,4 @@ main_start() {
}

# note: only start executing commands now to guard against partial downloads
main_start $@
main_start "$@"
4 changes: 2 additions & 2 deletions cmake/mimalloc-config-version.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
set(mi_version_major 2)
set(mi_version_minor 3)
set(mi_version_patch 2)
set(mi_version_minor 4)
set(mi_version_patch 1)
set(mi_version ${mi_version_major}.${mi_version_minor})

set(PACKAGE_VERSION ${mi_version})
Expand Down
2 changes: 1 addition & 1 deletion contrib/vcpkg/portfile.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ vcpkg_from_github(
REPO microsoft/mimalloc
HEAD_REF master

# The "REF" can be a commit hash, branch name (dev3), or a version (v3.3.2).
# The "REF" can be a commit hash, branch name (dev3), or a version (v3.4.1).
REF "v${VERSION}"
# REF e2db21e9ba9fb9172b7b0aa0fe9b8742525e8774

Expand Down
2 changes: 1 addition & 1 deletion contrib/vcpkg/vcpkg.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mimalloc",
"version": "3.3.2",
"version": "3.4.1",
"port-version": 0,
"description": "Compact general purpose allocator with excellent performance",
"homepage": "https://github.com/microsoft/mimalloc",
Expand Down
2 changes: 1 addition & 1 deletion doc/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ Notes:
- Generally it is recommended to download sources (or use `vcpkg` etc.) and build mimalloc as
part of your project.
- Source releases can also be downloaded directly from github by the tag.
For example <https://github.com/microsoft/mimalloc/archive/v3.3.2.tar.gz>.
For example <https://github.com/microsoft/mimalloc/archive/v3.4.0.tar.gz>.
- Binary releases include a release-, debug-, and secure build.
- Linux binaries are built on Ubuntu 22.
7 changes: 3 additions & 4 deletions include/mimalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file
#ifndef MIMALLOC_H
#define MIMALLOC_H

#define MI_MALLOC_VERSION 20302 // major + 2 digits minor + 2 digits patch
#define MI_MALLOC_VERSION 20401 // major + 2 digits minor + 2 digits patch

// ------------------------------------------------------
// Compiler specific attributes
Expand Down Expand Up @@ -95,7 +95,7 @@ terms of the MIT license. A copy of the license can be found in the file
// Includes
// ------------------------------------------------------

#include <stddef.h> // size_t
#include <stddef.h> // size_t, wchar_t
#include <stdbool.h> // bool
#include <stdint.h> // INTPTR_MAX

Expand Down Expand Up @@ -467,7 +467,7 @@ mi_decl_nodiscard mi_decl_export size_t mi_malloc_size(const void* p) mi_
mi_decl_nodiscard mi_decl_export size_t mi_malloc_good_size(size_t size) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept;

mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept;
mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size); // mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_pvalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
Expand All @@ -484,7 +484,6 @@ mi_decl_export void mi_free_aligned(void* p, size_t alignment)
mi_decl_export int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept;

// wide characters
#include <wchar.h> // wchar_t
mi_decl_export int mi_wdupenv_s(wchar_t** buf, size_t* size, const wchar_t* name) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export mi_decl_restrict wchar_t* mi_wcsdup(const wchar_t* s) mi_attr_noexcept mi_attr_malloc;
mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc;
Expand Down
42 changes: 40 additions & 2 deletions include/mimalloc/atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ static inline void mi_atomic_yield(void) {
#elif (defined(__GNUC__) || defined(__clang__)) && \
(defined(__x86_64__) || defined(__i386__) || \
defined(__aarch64__) || defined(__arm__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__))
defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__) || \
defined(__riscv))
#if defined(__x86_64__) || defined(__i386__)
static inline void mi_atomic_yield(void) {
__asm__ volatile ("pause" ::: "memory");
Expand Down Expand Up @@ -445,6 +446,16 @@ static inline void mi_atomic_yield(void) {
__asm__ __volatile__ ("or 27,27,27" ::: "memory");
}
#endif
#elif defined(__riscv)
#if defined(__riscv_zihintpause)
static inline void mi_atomic_yield(void) {
__asm__ volatile("pause" ::: "memory");
}
#else
static inline void mi_atomic_yield(void) {
__asm__ volatile("nop" ::: "memory");
}
#endif
#endif
#elif defined(__sun)
#include <synch.h>
Expand All @@ -469,6 +480,32 @@ static inline void mi_atomic_yield(void) {
}
#endif

#if defined(_WIN32)
static inline void mi_sleep0(void) {
Sleep(0);
}
#else
#include <unistd.h>
static inline void mi_sleep0(void) {
sleep(0);
}
#endif

static inline void mi_atomic_yield_sleep( size_t* ticks, const size_t ticks_until_sleep ) {
const size_t n = *ticks;
if (n==0 || n > ticks_until_sleep) {
*ticks = ticks_until_sleep; // reset
}
else {
*ticks = n-1;
}
if (n>1) {
mi_atomic_yield();
}
else {
mi_sleep0();
}
}

// ----------------------------------------------------------------------
// Locks
Expand Down Expand Up @@ -589,9 +626,10 @@ static inline bool mi_lock_try_acquire(mi_lock_t* lock) {
return mi_atomic_cas_strong_acq_rel(&lock->mutex, &expected, (uintptr_t)1);
}
static inline void mi_lock_acquire(mi_lock_t* lock) {
size_t ticks = 0;
for (int i = 0; i < 10000; i++) { // for at most 10000 tries?
if (mi_lock_try_acquire(lock)) return;
mi_atomic_yield();
mi_atomic_yield_sleep(&ticks,100);
}
_mi_error_message(EFAULT, "internal error: lock cannot be acquired (due to lack of native lock primitives)\n");
}
Expand Down
7 changes: 5 additions & 2 deletions include/mimalloc/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void _mi_strlcat(char* dest, const char* src, size_t dest_size);
size_t _mi_strlen(const char* s);
size_t _mi_strnlen(const char* s, size_t max_len);
bool _mi_streq(const char* s, const char* t);
bool _mi_getenv(const char* name, char* result, size_t result_size);
int _mi_getenv(const char* name, char* result, size_t result_size);

// "options.c"
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
Expand Down Expand Up @@ -320,6 +320,9 @@ bool _mi_page_is_valid(mi_page_t* page);
#ifndef EOVERFLOW // count*size overflow
#define EOVERFLOW (75)
#endif
#ifndef ENOENT // environment variable not found
#define ENOENT (2)
#endif


// ------------------------------------------------------
Expand Down Expand Up @@ -718,7 +721,7 @@ static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void*
#else
MI_UNUSED(block); MI_UNUSED(p);
return false;
#endif
#endif
}

#if MI_GUARDED
Expand Down
15 changes: 13 additions & 2 deletions include/mimalloc/prim.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ void _mi_prim_out_stderr( const char* msg );

// Get an environment variable. (only for options)
// name != NULL, result != NULL, result_size >= 64
bool _mi_prim_getenv(const char* name, char* result, size_t result_size);
// Return 1 for success, 0 if not found,
// and -1 on error (for example, if `getenv` cannot be called yet during preloading).
int _mi_prim_getenv(const char* name, char* result, size_t result_size);


// Fill a buffer with strong randomness; return `false` on error or if
Expand Down Expand Up @@ -139,7 +141,7 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap);
// but unfortunately we can not detect support reliably (see issue #883)
// We also use it on Apple OS as we use a TLS slot for the default heap there.
#if defined(__GNUC__) && ( \
(defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \
(defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) || defined(__riscv))) \
|| (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__) || defined(__POWERPC__))) \
|| (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \
|| (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \
Expand Down Expand Up @@ -171,6 +173,10 @@ static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept {
__asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb));
#endif
res = tcb[slot];
#elif defined(__riscv)
void** tcb; MI_UNUSED(ofs);
__asm__ volatile ("mv %0, tp" : "=r" (tcb));
res = tcb[slot];
#elif defined(__APPLE__) && defined(__POWERPC__) // ppc, issue #781
MI_UNUSED(ofs);
res = pthread_getspecific(slot);
Expand Down Expand Up @@ -201,6 +207,10 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce
__asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb));
#endif
tcb[slot] = value;
#elif defined(__riscv)
void** tcb; MI_UNUSED(ofs);
__asm__ volatile ("mv %0, tp" : "=r" (tcb));
tcb[slot] = value;
#elif defined(__APPLE__) && defined(__POWERPC__) // ppc, issue #781
MI_UNUSED(ofs);
pthread_setspecific(slot, value);
Expand Down Expand Up @@ -263,6 +273,7 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce
&& !defined(MI_LIBC_MUSL) \
&& (!defined(__clang_major__) || __clang_major__ >= 14) /* older clang versions emit bad code; fall back to using the TLS slot (<https://lore.kernel.org/linux-arm-kernel/202110280952.352F66D8@keescook/T/>) */
#if (defined(__GNUC__) && (__GNUC__ >= 7) && defined(__aarch64__)) /* aarch64 for older gcc versions (issue #851) */ \
|| (defined(__GNUC__) && (__GNUC__ >= 7) && defined(__riscv)) \
|| (defined(__GNUC__) && (__GNUC__ >= 11) && defined(__x86_64__)) \
|| (defined(__clang_major__) && (__clang_major__ >= 14) && (defined(__aarch64__) || defined(__x86_64__)))
#define MI_USE_BUILTIN_THREAD_POINTER 1
Expand Down
2 changes: 1 addition & 1 deletion include/mimalloc/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ typedef struct mi_subproc_s mi_subproc_t;
typedef struct mi_segment_s {
// constant fields
mi_memid_t memid; // memory id for arena/OS allocation
bool allow_decommit; // can we decommmit the memory
bool allow_decommit; // can we decommit the memory
bool allow_purge; // can we purge the memory (reset or decommit)
size_t segment_size;
mi_subproc_t* subproc; // segment belongs to sub process
Expand Down
10 changes: 7 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ is a general purpose allocator with excellent [performance](#performance) charac
Initially developed by Daan Leijen for the runtime systems of the
[Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages.

Latest release : `v3.3.2` (2026-04-29) recommended.
Latest v2 release: `v2.3.2` (2026-04-29) stable.
Latest v1 release: `v1.9.10` (2026-04-29) legacy.
Latest release : `v3.4.1` (2026-07-14) recommended.
Latest v2 release: `v2.4.1` (2026-07-14) stable.
Latest v1 release: `v1.9.11` (2026-07-14) legacy.

mimalloc is a drop-in replacement for `malloc` and can be used in other programs
without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as:
Expand Down Expand Up @@ -88,6 +88,10 @@ New development is mostly on v3, while v1 and v2 are maintained with security an
- __v1__: legacy version: initial design of mimalloc (release tags: `v1.9.x`, development branch `dev`). Send PR's against this version if possible.

### Releases
* 2026-07-14, `v1.9.11`, `v2.4.1`, `v3.4.1`: various bug and security fixes through LLM audit (by @Zoxc).
Fix issue with using OS memory instead of arenas for > 4GiB memory usage (v3), fix concurrency bug in concurrent
heap destroy (v3), detect riscV virtual address bits at runtime, add riscV TLS support, reduce spinlock waits (v2),
use TLS slots 126/127 on macOS (v3), and other small fixes. All metadata is now separated from heap objects in v3.
* 2026-04-29, `v1.9.10`, `v2.3.2`, `v3.3.2`: various bug and security fixes through LLM audit (by @Zoxc).
Only increase minimal purge size automatically if allow_thp is set to 2. Enable large OS alignment
on all platforms (fixing OS large pages on Windows). Fix accounting of committed memory on Linux/macOS.
Expand Down
2 changes: 1 addition & 1 deletion src/alloc-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void mi_cfree(void* p) mi_attr_noexcept {
}
}

int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept {
int mi_posix_memalign(void** p, size_t alignment, size_t size) { // mi_attr_noexcept (issue #794)
// Note: The spec dictates we should not modify `*p` on an error. (issue#27)
// <http://man7.org/linux/man-pages/man3/posix_memalign.3.html>
if (p == NULL) return EINVAL;
Expand Down
4 changes: 2 additions & 2 deletions src/arena.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,12 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi

// checks
if (arena == NULL) {
_mi_error_message(EINVAL, "trying to free from an invalid arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
_mi_error_message(EINVAL, "trying to free from an invalid arena: %p, size %zu, memkind: 0x%x\n", p, size, memid.memkind);
return;
}
mi_assert_internal(arena->field_count > mi_bitmap_index_field(bitmap_idx));
if (arena->field_count <= mi_bitmap_index_field(bitmap_idx)) {
_mi_error_message(EINVAL, "trying to free from an invalid arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
_mi_error_message(EINVAL, "trying to free from an invalid arena block: %p, size %zu, memid: 0x%x\n", p, size, memid.memkind);
return;
}

Expand Down
6 changes: 5 additions & 1 deletion src/heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)

// free all current thread delayed blocks.
// (if abandoning, after this there are no more thread-delayed references into the pages.)
_mi_heap_delayed_free_all(heap);
if (collect >= MI_ABANDON) {
_mi_heap_delayed_free_all(heap); // free all
} else {
_mi_heap_delayed_free_partial(heap); // best-effort; contended blocks are retried next time
}

// collect retired pages
_mi_heap_collect_retired(heap, force);
Expand Down
Loading