3.5.1+: mi_free_size uses mi_free_small for small sizes with MI_PAGE_META_IS_ALIGNED, corrupting the heap when a larger block is freed with a small size
维护者通常 3 天内回复
评估
调研方向
Start in src/free.c at the mi_free_size branch changed between v3.5.0 and v3.5.1, then build and run the supplied C++ reproducer with the stated release configurations. Compare the page-alignment and page-map paths, and verify that the completed change prevents heap corruption while preserving appropriate handling of an undersized delete.
由索引模型根据 Issue 内容生成。
描述
Summary
Since v3.5.1, mi_free_size (used by sized operator delete(void*, size_t)) takes the mi_free_small path for any size <= MI_SMALL_SIZE_MAX when MI_PAGE_META_IS_ALIGNED is set. mi_free_small finds the page by aligning the pointer down instead of using the page map, so if the block actually lives in a larger page, the "page" header is garbage and the heap is corrupted (SEGV in _mi_page_free_collect / mi_page_update_sample_countdown via mi_free_try_collect_mt, or corrupted thread-free list (possibly due to a cross-thread double free)).
Up to v3.5.0 the same code worked in practice (the #if was MI_PAGE_META_SMALL_IS_ALIGNED only, so the regular page-map lookup was used).
I realize the caller is technically at fault: the block was allocated with malloc(2000+) but released with a sized delete whose size is tiny (std::unique_ptr<T> default deleter on a variable-size record with a flexible array member, sizeof(T)==4). This is UB per the C++ standard, and we are fixing our code. I'm reporting because (a) this was a silent behavior change in a patch release, and a hard-to-diagnose crash in release builds, and (b) debug and secure builds of 3.5.3 do not report it (no mi_free_size ... less than the allocated block size message and no crash in our real application), so it is very hard to find. Perhaps release builds could keep the page-map lookup for mi_free_size, or the docs could mention the requirement.
Reproducer
#include <cstdlib>
#include <cstring>
#include <memory>
#include <thread>
#include <vector>
#include <cstdio>
struct Extra { unsigned a; unsigned char data[]; };
int main() {
for (int round = 0; round < 200; ++round) {
std::vector<std::unique_ptr<Extra>> v;
for (int i = 0; i < 2000; ++i) {
size_t sz = 2000 + (i % 7) * 3000; // > MI_SMALL_SIZE_MAX
auto* p = static_cast<Extra*>(malloc(sz));
memset(p, 0, sz);
v.emplace_back(p); // default_delete -> operator delete(p, sizeof(Extra)==4)
}
std::thread t([&] { v.clear(); }); // cross-thread free
t.join();
std::vector<void*> junk; // churn the same pages
for (int i = 0; i < 5000; ++i) junk.push_back(malloc(3000));
for (auto* j : junk) free(j);
}
puts("done");
}
Build (shared mimalloc, release, default CMake options, -DMI_USE_CXX=ON):
g++ -O2 -fsized-deallocation repro.cpp -o repro /path/to/libmimalloc.so.3 -pthread
Results (Rocky Linux 9.8, glibc 2.34, GCC 15.2, x86_64, Release builds from the GitHub tags)
| mimalloc | result |
|---|---|
| v3.4.5 | done |
| v3.5.0 | done |
| v3.5.1 | SIGSEGV |
| v3.5.3 | SIGSEGV |
| v3.5.4 | SIGSEGV |
In our real application (a gRPC server, free from a different thread) the same change shows: 3.4.5 and 3.5.0 pass, 3.5.1/3.5.2/3.5.3/3.5.4 crash (several full runs each), while v3.5.3 built with MI_DEBUG_FULL=ON or MI_SECURE=ON ran clean. MI_PROFILE=OFF does not help.
Diffing v3.5.0..v3.5.1, src/free.c changes mi_free_size from #if MI_PAGE_META_SMALL_IS_ALIGNED to #if MI_PAGE_META_SMALL_IS_ALIGNED || MI_PAGE_META_IS_ALIGNED for the size <= MI_SMALL_SIZE_MAX branch calling mi_free_small(p), which I believe is the trigger.
- 主要语言
- C
- 星标
- 13.4k
- 派生
- 1.2k
- 平均合并
- 3 天 20 小时
- 30 天内合并 PR
- 8
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
microsoft/mimalloc 的其他 Issue
-
Mimalloc arena `mi_heap_malloc_aligned` has a hidden limit on max alignment of 64 KiB per allocation可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 68/100
microsoft/mimalloc#1406 · 2 条评论 ·
维护者通常 3 天内回复
-
stale
难度 2/5 1-3 小时 新手友好度 74/100
microsoft/mimalloc#1113 · 1 条评论 ·
维护者通常 3 天内回复
-
难度 2/5 1-3 小时 新手友好度 65/100
microsoft/mimalloc#886 · 4 条评论 · 1 个 reaction ·
维护者通常 3 天内回复
-
难度 2/5 1-3 小时 新手友好度 64/100
microsoft/mimalloc#368 · 1 条评论 ·
维护者通常 3 天内回复
-
难度 4/5 3-5 天 新手友好度 45/100
microsoft/mimalloc#1426 · 3 条评论 ·
维护者通常 3 天内回复
查看 microsoft/mimalloc 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 70/100
DaveGamble/cJSON#1100 ·
-
area:runtime-vm
难度 2/5 1-3 小时 新手友好度 72/100
InauguralSystems/EigenScript#1748 ·
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 76/100
leanprover/lean4#15677 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 2 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 68/100
wasm-micro-runtime/wasm-micro-runtime#5159 ·
维护者通常 7 天内回复