@@ -19,12 +19,12 @@ const mi_page_t _mi_page_empty = {
1919 false, // is_zero
2020 0 , // retire_expire
2121 NULL , // free
22- #if MI_ENCODE_FREELIST
23- { 0 , 0 },
24- #endif
2522 0 , // used
2623 0 , // xblock_size
2724 NULL , // local_free
25+ #if MI_ENCODE_FREELIST
26+ { 0 , 0 },
27+ #endif
2828 MI_ATOMIC_VAR_INIT (0 ), // xthread_free
2929 MI_ATOMIC_VAR_INIT (0 ), // xheap
3030 NULL , NULL
@@ -109,8 +109,9 @@ mi_decl_cache_align const mi_heap_t _mi_heap_empty = {
109109 MI_ATOMIC_VAR_INIT (NULL ),
110110 0 , // tid
111111 0 , // cookie
112+ 0 , // arena id
112113 { 0 , 0 }, // keys
113- { {0 }, {0 }, 0 },
114+ { {0 }, {0 }, 0 , true }, // random
114115 0 , // page count
115116 MI_BIN_FULL , 0 , // page retired min/max
116117 NULL , // next
@@ -149,8 +150,9 @@ mi_heap_t _mi_heap_main = {
149150 MI_ATOMIC_VAR_INIT (NULL ),
150151 0 , // thread id
151152 0 , // initial cookie
153+ 0 , // arena id
152154 { 0 , 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!)
153- { {0x846ca68b }, {0 }, 0 }, // random
155+ { {0x846ca68b }, {0 }, 0 , true }, // random
154156 0 , // page count
155157 MI_BIN_FULL , 0 , // page retired min/max
156158 NULL , // next heap
@@ -165,8 +167,13 @@ mi_stats_t _mi_stats_main = { MI_STATS_NULL };
165167static void mi_heap_main_init (void ) {
166168 if (_mi_heap_main .cookie == 0 ) {
167169 _mi_heap_main .thread_id = _mi_thread_id ();
168- _mi_heap_main .cookie = _mi_os_random_weak ((uintptr_t )& mi_heap_main_init );
169- _mi_random_init (& _mi_heap_main .random );
170+ _mi_heap_main .cookie = 1 ;
171+ #if defined(_WIN32 ) && !defined(MI_SHARED_LIB )
172+ _mi_random_init_weak (& _mi_heap_main .random ); // prevent allocation failure during bcrypt dll initialization with static linking
173+ #else
174+ _mi_random_init (& _mi_heap_main .random );
175+ #endif
176+ _mi_heap_main .cookie = _mi_heap_random_next (& _mi_heap_main );
170177 _mi_heap_main .keys [0 ] = _mi_heap_random_next (& _mi_heap_main );
171178 _mi_heap_main .keys [1 ] = _mi_heap_random_next (& _mi_heap_main );
172179 }
@@ -372,7 +379,11 @@ static void _mi_thread_done(mi_heap_t* default_heap);
372379 #endif
373380 static DWORD mi_fls_key = (DWORD )(-1 );
374381 static void NTAPI mi_fls_done (PVOID value ) {
375- if (value != NULL ) _mi_thread_done ((mi_heap_t * )value );
382+ mi_heap_t * heap = (mi_heap_t * )value ;
383+ if (heap != NULL ) {
384+ _mi_thread_done (heap );
385+ FlsSetValue (mi_fls_key , NULL ); // prevent recursion as _mi_thread_done may set it back to the main heap, issue #672
386+ }
376387 }
377388#elif defined(MI_USE_PTHREADS )
378389 // use pthread local storage keys to detect thread ending
@@ -475,7 +486,7 @@ void _mi_heap_set_default_direct(mi_heap_t* heap) {
475486// --------------------------------------------------------
476487// Run functions on process init/done, and thread init/done
477488// --------------------------------------------------------
478- static void mi_process_done (void );
489+ static void mi_cdecl mi_process_done (void );
479490
480491static bool os_preloading = true; // true until this module is initialized
481492static bool mi_redirected = false; // true if malloc redirects to mi_malloc
@@ -490,7 +501,7 @@ mi_decl_nodiscard bool mi_is_redirected(void) mi_attr_noexcept {
490501}
491502
492503// Communicate with the redirection module on Windows
493- #if defined(_WIN32 ) && defined(MI_SHARED_LIB )
504+ #if defined(_WIN32 ) && defined(MI_SHARED_LIB ) && !defined( MI_WIN_NOREDIRECT )
494505#ifdef __cplusplus
495506extern "C" {
496507#endif
@@ -506,8 +517,8 @@ mi_decl_export void _mi_redirect_entry(DWORD reason) {
506517 mi_thread_done ();
507518 }
508519}
509- __declspec(dllimport ) bool mi_allocator_init (const char * * message );
510- __declspec(dllimport ) void mi_allocator_done (void );
520+ __declspec(dllimport ) bool mi_cdecl mi_allocator_init (const char * * message );
521+ __declspec(dllimport ) void mi_cdecl mi_allocator_done (void );
511522#ifdef __cplusplus
512523}
513524#endif
@@ -529,12 +540,13 @@ static void mi_process_load(void) {
529540 MI_UNUSED (dummy );
530541 #endif
531542 os_preloading = false;
543+ mi_assert_internal (_mi_is_main_thread ());
532544 #if !(defined(_WIN32 ) && defined(MI_SHARED_LIB )) // use Dll process detach (see below) instead of atexit (issue #521)
533545 atexit (& mi_process_done );
534546 #endif
535547 _mi_options_init ();
548+ mi_process_setup_auto_thread_done ();
536549 mi_process_init ();
537- //mi_stats_reset();-
538550 if (mi_redirected ) _mi_verbose_message ("malloc is redirected.\n" );
539551
540552 // show message from the redirector (if present)
@@ -543,6 +555,9 @@ static void mi_process_load(void) {
543555 if (msg != NULL && (mi_option_is_enabled (mi_option_verbose ) || mi_option_is_enabled (mi_option_show_errors ))) {
544556 _mi_fputs (NULL ,NULL ,NULL ,msg );
545557 }
558+
559+ // reseed random
560+ _mi_random_reinit_if_weak (& _mi_heap_main .random );
546561}
547562
548563#if defined(_WIN32 ) && (defined(_M_IX86 ) || defined(_M_X64 ))
@@ -569,14 +584,14 @@ void mi_process_init(void) mi_attr_noexcept {
569584 _mi_process_is_initialized = true;
570585 mi_process_setup_auto_thread_done ();
571586
572-
573587 mi_detect_cpu_features ();
574588 _mi_os_init ();
575589 mi_heap_main_init ();
576590 #if (MI_DEBUG )
577591 _mi_verbose_message ("debug level : %d\n" , MI_DEBUG );
578592 #endif
579593 _mi_verbose_message ("secure level: %d\n" , MI_SECURE );
594+ _mi_verbose_message ("mem tracking: %s\n" , MI_TRACK_TOOL );
580595 mi_thread_init ();
581596
582597 #if defined(_WIN32 ) && !defined(MI_SHARED_LIB )
@@ -606,7 +621,7 @@ void mi_process_init(void) mi_attr_noexcept {
606621}
607622
608623// Called when the process is done (through `at_exit`)
609- static void mi_process_done (void ) {
624+ static void mi_cdecl mi_process_done (void ) {
610625 // only shutdown if we were initialized
611626 if (!_mi_process_is_initialized ) return ;
612627 // ensure we are called once
@@ -627,6 +642,14 @@ static void mi_process_done(void) {
627642 #endif
628643 #endif
629644
645+ // Forcefully release all retained memory; this can be dangerous in general if overriding regular malloc/free
646+ // since after process_done there might still be other code running that calls `free` (like at_exit routines,
647+ // or C-runtime termination code.
648+ if (mi_option_is_enabled (mi_option_destroy_on_exit )) {
649+ _mi_heap_destroy_all (); // forcefully release all memory held by all heaps (of this thread only!)
650+ _mi_segment_cache_free_all (& _mi_heap_main_get ()-> tld -> os ); // release all cached segments
651+ }
652+
630653 if (mi_option_is_enabled (mi_option_show_stats ) || mi_option_is_enabled (mi_option_verbose )) {
631654 mi_stats_print (NULL );
632655 }
0 commit comments