From 9f70ce5fcd5e59d0b6eeb5094566b8b7711e4d13 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:34:02 -0800 Subject: [PATCH] avoid accessing heap->tld after running thread_done (pr #974) --- include/mimalloc/internal.h | 2 +- src/heap.c | 7 ++++--- src/init.c | 11 ++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 0ede8f8c..a1791cd9 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -216,7 +216,7 @@ void _mi_heap_destroy_pages(mi_heap_t* heap); void _mi_heap_collect_abandon(mi_heap_t* heap); void _mi_heap_set_default_direct(mi_heap_t* heap); bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); -void _mi_heap_unsafe_destroy_all(void); +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap); mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); diff --git a/src/heap.c b/src/heap.c index c2b5ae42..7a14c1aa 100644 --- a/src/heap.c +++ b/src/heap.c @@ -393,9 +393,10 @@ void mi_heap_destroy(mi_heap_t* heap) { } // forcefully destroy all heaps in the current thread -void _mi_heap_unsafe_destroy_all(void) { - mi_heap_t* bheap = mi_heap_get_backing(); - mi_heap_t* curr = bheap->tld->heaps; +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap) { + mi_assert_internal(heap != NULL); + if (heap == NULL) return; + mi_heap_t* curr = heap->tld->heaps; while (curr != NULL) { mi_heap_t* next = curr->next; if (curr->no_reclaim) { diff --git a/src/init.c b/src/init.c index b8c01e51..734bf5de 100644 --- a/src/init.c +++ b/src/init.c @@ -663,15 +663,20 @@ void mi_cdecl _mi_process_done(void) { if (process_done) return; process_done = true; + // get the default heap so we don't need to acces thread locals anymore + mi_heap_t* heap = mi_prim_get_default_heap(); // use prim to not initialize any heap + mi_assert_internal(heap != NULL); + // release any thread specific resources and ensure _mi_thread_done is called on all but the main thread _mi_prim_thread_done_auto_done(); + #ifndef MI_SKIP_COLLECT_ON_EXIT #if (MI_DEBUG || !defined(MI_SHARED_LIB)) // free all memory if possible on process exit. This is not needed for a stand-alone process // but should be done if mimalloc is statically linked into another shared library which // is repeatedly loaded/unloaded, see issue #281. - mi_collect(true /* force */ ); + mi_heap_collect(heap, true /* force */ ); #endif #endif @@ -679,8 +684,8 @@ void mi_cdecl _mi_process_done(void) { // since after process_done there might still be other code running that calls `free` (like at_exit routines, // or C-runtime termination code. if (mi_option_is_enabled(mi_option_destroy_on_exit)) { - mi_collect(true /* force */); - _mi_heap_unsafe_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) + mi_heap_collect(heap, true /* force */); + _mi_heap_unsafe_destroy_all(heap); // forcefully release all memory held by all heaps (of this thread only!) _mi_arena_unsafe_destroy_all(); _mi_segment_map_unsafe_destroy(); }