Skip to content

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

Description

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

#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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions