LibC: Prevent assertions in malloc/free at exit time

This is a bit sad, but, with the Allocators as static globals their
destructors were running before some user code. Which doesn't really
make much sense, as none of the members of (at least the basic one) do
any real heavy lifting or have many resources to RAII.

To avoid the problem, just mmap the memory for the global arrays of
Allocators in __malloc_init and let the Kernel collect the memory when
we're done with the process.
This commit is contained in:
Andrew Kaster 2019-12-22 02:06:50 -07:00 committed by Andreas Kling
parent 7edfdca4b2
commit 150837e7e8
Notes: sideshowbarker 2024-07-19 10:46:30 +09:00
2 changed files with 25 additions and 2 deletions

View File

@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
//#define GLOBAL_DTORS_DEBUG
extern "C" {
int main(int, char**, char**);
@ -83,11 +85,18 @@ void __cxa_finalize(void* dso_handle)
int entry_index = __exit_entry_count;
#ifdef GLOBAL_DTORS_DEBUG
dbgprintf("__cxa_finalize: %d entries in the finalizer list\n", entry_index);
#endif
while (--entry_index >= 0)
{
auto& exit_entry = __exit_entries[entry_index];
bool needs_calling = !exit_entry.has_been_called && (!dso_handle || dso_handle == exit_entry.dso_handle);
if (needs_calling) {
#ifdef GLOBAL_DTORS_DEBUG
dbgprintf("__cxa_finalize: calling entry[%d] %p(%p) dso: %p\n", entry_index, exit_entry.method, exit_entry.parameter, exit_entry.dso_handle);
#endif
exit_entry.method(exit_entry.parameter);
exit_entry.has_been_called = true;
}

View File

@ -99,8 +99,9 @@ struct BigAllocator {
Vector<BigAllocationBlock*, number_of_big_blocks_to_keep_around_per_size_class> blocks;
};
static Allocator g_allocators[num_size_classes];
static BigAllocator g_big_allocators[1];
// Allocators will be mmapped in __malloc_init
Allocator* g_allocators = nullptr;
BigAllocator* g_big_allocators = nullptr;
static Allocator* allocator_for_size(size_t size, size_t& good_size)
{
@ -369,5 +370,18 @@ void __malloc_init()
s_scrub_free = false;
if (getenv("LIBC_LOG_MALLOC"))
s_log_malloc = true;
g_allocators = (Allocator*)mmap_with_name(nullptr, sizeof(Allocator) * num_size_classes, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "LibC Allocators");
for (size_t i = 0; i < num_size_classes; ++i) {
new (&g_allocators[i]) Allocator();
g_allocators[i].size = size_classes[i];
}
g_big_allocators = (BigAllocator*)mmap_with_name(nullptr, sizeof(BigAllocator), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "LibC BigAllocators");
new (g_big_allocators) (BigAllocator);
// We could mprotect the mmaps here with atexit, but, since this method is called in _start before
// _init and __init_array entries, our mprotect method would always be the last thing run before _exit.
}
}