microsoft / mimalloc

mimalloc is a compact general purpose allocator with excellent performance.
MIT License
9.74k stars 791 forks source link

2.1.4: crash in mi_segment_try_purge during mi_process_done #904

Closed epoupon closed 4 weeks ago

epoupon commented 1 month ago

Hello,

Using windows, static build, with mimalloc 2.1.4, here is the test case:

A thread creates a heap, performs an allocation in it, and calls mi_heap_delete. The thread is then destroyed.

Later when the process shuts down, we have this crash:

test.exe!mi_segment_try_purge(mi_segment_s * segment, bool force, mi_stats_s * stats) Line 569
test.exe!mi_heap_page_collect(mi_heap_s * heap, mi_page_queue_s * pq, mi_page_s * page, void * arg_collect, void * arg2) Line 111
test.exe!mi_heap_visit_pages(mi_heap_s * heap, bool(*)(mi_heap_s *, mi_page_queue_s *, mi_page_s *, void *, void *) fn, void * arg1, void * arg2) Line 46
test.exe!mi_heap_collect_ex(mi_heap_s * heap, mi_collect_e collect) Line 163
test.exe!mi_heap_collect(mi_heap_s * heap, bool force) Line 180
test.exe!mi_collect(bool force) Line 184
test.exe!mi_process_done() Line 641

Exception thrown: read access violation. segment was 0x353EA000000.

When inspecting callstack at mi_heap_page_collect, it looks like page was actually already unmapped. Calling mi_heap_collect before calling mi_heap_delete makes the crash disappear.

Is this known?

(by the way, the API doc of mi_heap_delete states:

This will release resources and migrate any still allocated blocks in this heap (efficienty) to the default heap.

But the code seems to use the backing heap to migrate allocated blocks)

daanx commented 1 month ago

Ah, I think this is fixed in v2.1.7. see commit: https://github.com/microsoft/mimalloc/commit/d824b9db2b339650b4dd04ffae5ede8abd84889c

Can you try that?

epoupon commented 3 weeks ago

Hello! Thanks for your answer, I do confirm it is fixed in 2.1.7!