microsoft / microsoft/mimalloc
SegFault: mi_free_size_aligned / mi_free_size on small over-aligned allocations v3
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 13.4k
- Forks
- 1.2k
- Avg merge
- 4d 45m
- Merged PRs (30d)
- 13
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
```c
#include
#include
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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/static.c at mi_free_size_aligned and mi_free_size, using the issue's C reproducer and release-build command to observe the failure. Trace how the supplied size and alignment reach the freeing path, then rerun the reproducer in the stated release configuration; done means matching aligned allocations can be freed without a crash.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100