#1400·mimalloc

SegFault: mi_free_size_aligned / mi_free_size on small over-aligned allocations v3

Author: MnwaCreated Sep 14, 2026Updated Sep 14, 2026

In mimalloc v3 release builds, mi_free_size(p, size) routes every size <= MI_SMALL_SIZE_MAX through mi_free_small, which locates the page by aligning p down to MI_SMALL_PAGE_SIZE instead of doing a page-map lookup. That is only valid when the block lives in a small page. A small block with a large alignment is over-allocated (size + alignment - 1) and ends up in a medium page, so the computed page pointer is garbage and the process crashes.

mi_free_size_aligned(p, size, alignment) receives the alignment but discards it and defers to mi_free_size, so calling it with exactly the documented inputs ("the size of the object as allocated", "the requested alignment at the allocation") is enough to trigger the crash.

Reproducer

c
#include <mimalloc.h>
#include <stdio.h>

int main(void) {
  const size_t size = 8;
  const size_t alignment = 16 * 1024;
  void* ptrs[200];
  for (int i = 0; i < 200; i++) {
    ptrs[i] = mi_malloc_aligned(size, alignment);
  }
  for (int i = 0; i < 200; i++) {
    mi_free_size_aligned(ptrs[i], size, alignment);   // SIGSEGV
  }
  printf("ok\n");
  return 0;
}
$ cc -O2 -DNDEBUG -DMI_DEBUG=0 -Iinclude src/static.c repro.c -o repro && ./repro
Segmentation fault (exit 139)

A single allocation does not always crash: the first block happens to sit in the first 64 KiB chunk of the medium page, where the aligned-down address coincides with the page header. With a handful of blocks the crash is deterministic.

The debug build detects the exact condition and recovers:

$ cc -O0 -DMI_DEBUG=3 -DMI_SHOW_ERRORS=1 -Iinclude src/static.c repro.c -o repro_dbg && ./repro_dbg
mimalloc: error: thread 0x...: pointer 0x020000100000 is freed with mi_free_size but the given size 8 is less than the allocated block size 20480
  (maybe a `new[]` was matched with `delete` instead of `delete[]`?)
...
ok

Expected

mi_free_size_aligned (and mi_free_size) should be safe for any pointer returned by the matching allocation call with the same size and alignment.

Environment

  • mimalloc v3.5.2 (same code present on current dev3)
  • macOS 26 (Darwin 25.6.0), arm64, Apple clang 21
  • Default build options, MI_SECURE off, MI_GUARDED off (both of those disable MI_PAGE_META_SMALL_IS_ALIGNED and avoid the crash). v2 is unaffected because its mi_free_size is a plain mi_free.

Found while evaluating mi_free_size_aligned for GlobalAlloc::dealloc in a Rust wrapper, where the allocator must accept any power-of-two alignment.