mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-07-01 01:04:37 +03:00
potential fix for use-after-free of the tld on unsafe arenas destroy
This commit is contained in:
parent
99976d6c2b
commit
aaf8da9aba
3 changed files with 9 additions and 10 deletions
|
@ -223,7 +223,7 @@ void* _mi_arenas_alloc_aligned(mi_subproc_t* subproc, size_t size, size_
|
|||
void _mi_arenas_free(void* p, size_t size, mi_memid_t memid);
|
||||
bool _mi_arenas_contain(const void* p);
|
||||
void _mi_arenas_collect(bool force_purge, bool visit_all, mi_tld_t* tld);
|
||||
void _mi_arenas_unsafe_destroy_all(mi_tld_t* tld);
|
||||
void _mi_arenas_unsafe_destroy_all(mi_subproc_t* subproc);
|
||||
|
||||
mi_page_t* _mi_arenas_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment);
|
||||
void _mi_arenas_page_free(mi_page_t* page, mi_tld_t* tld);
|
||||
|
|
15
src/arena.c
15
src/arena.c
|
@ -993,7 +993,7 @@ void _mi_arenas_page_unabandon(mi_page_t* page) {
|
|||
Arena free
|
||||
----------------------------------------------------------- */
|
||||
static void mi_arena_schedule_purge(mi_arena_t* arena, size_t slice_index, size_t slices);
|
||||
static void mi_arenas_try_purge(bool force, bool visit_all, mi_tld_t* tld);
|
||||
static void mi_arenas_try_purge(bool force, bool visit_all, mi_subproc_t* subproc, size_t tseq);
|
||||
|
||||
void _mi_arenas_free(void* p, size_t size, mi_memid_t memid) {
|
||||
if (p==NULL) return;
|
||||
|
@ -1054,7 +1054,7 @@ void _mi_arenas_free(void* p, size_t size, mi_memid_t memid) {
|
|||
|
||||
// Purge the arenas; if `force_purge` is true, amenable parts are purged even if not yet expired
|
||||
void _mi_arenas_collect(bool force_purge, bool visit_all, mi_tld_t* tld) {
|
||||
mi_arenas_try_purge(force_purge, visit_all, tld);
|
||||
mi_arenas_try_purge(force_purge, visit_all, tld->subproc, tld->thread_seq);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1109,9 +1109,9 @@ static void mi_arenas_unsafe_destroy(mi_subproc_t* subproc) {
|
|||
|
||||
// destroy owned arenas; this is unsafe and should only be done using `mi_option_destroy_on_exit`
|
||||
// for dynamic libraries that are unloaded and need to release all their allocated memory.
|
||||
void _mi_arenas_unsafe_destroy_all(mi_tld_t* tld) {
|
||||
mi_arenas_unsafe_destroy(tld->subproc);
|
||||
_mi_arenas_collect(true /* force purge */, true /* visit all*/, tld); // purge non-owned arenas
|
||||
void _mi_arenas_unsafe_destroy_all(mi_subproc_t* subproc) {
|
||||
mi_arenas_unsafe_destroy(subproc);
|
||||
mi_arenas_try_purge(true /* force purge */, true /* visit all*/, subproc, 0 /* thread seq */); // purge non-owned arenas
|
||||
}
|
||||
|
||||
|
||||
|
@ -1775,14 +1775,13 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force)
|
|||
}
|
||||
|
||||
|
||||
static void mi_arenas_try_purge(bool force, bool visit_all, mi_tld_t* tld)
|
||||
static void mi_arenas_try_purge(bool force, bool visit_all, mi_subproc_t* subproc, size_t tseq)
|
||||
{
|
||||
// try purge can be called often so try to only run when needed
|
||||
const long delay = mi_arena_purge_delay();
|
||||
if (_mi_preloading() || delay <= 0) return; // nothing will be scheduled
|
||||
|
||||
// check if any arena needs purging?
|
||||
mi_subproc_t* subproc = tld->subproc;
|
||||
const mi_msecs_t now = _mi_clock_now();
|
||||
const mi_msecs_t arenas_expire = mi_atomic_loadi64_acquire(&subproc->purge_expire);
|
||||
if (!visit_all && !force && (arenas_expire == 0 || arenas_expire > now)) return;
|
||||
|
@ -1796,7 +1795,7 @@ static void mi_arenas_try_purge(bool force, bool visit_all, mi_tld_t* tld)
|
|||
{
|
||||
// increase global expire: at most one purge per delay cycle
|
||||
if (arenas_expire > now) { mi_atomic_storei64_release(&subproc->purge_expire, now + (delay/10)); }
|
||||
const size_t arena_start = tld->thread_seq % max_arena;
|
||||
const size_t arena_start = tseq % max_arena;
|
||||
size_t max_purge_count = (visit_all ? max_arena : (max_arena/4)+1);
|
||||
bool all_visited = true;
|
||||
bool any_purged = false;
|
||||
|
|
|
@ -778,7 +778,7 @@ void mi_cdecl mi_process_done(void) mi_attr_noexcept {
|
|||
if (mi_option_is_enabled(mi_option_destroy_on_exit)) {
|
||||
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_arenas_unsafe_destroy_all(heap->tld);
|
||||
_mi_arenas_unsafe_destroy_all(_mi_subproc_main());
|
||||
_mi_page_map_unsafe_destroy(_mi_subproc_main());
|
||||
}
|
||||
//_mi_page_map_unsafe_destroy(_mi_subproc_main());
|
||||
|
|
Loading…
Add table
Reference in a new issue