From f474606ee92a7afddb5b3b6350a97ffd31e22c42 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Wed, 12 Aug 2015 20:53:59 +0200 Subject: [PATCH] libroot_debug: Merge guarded heap into libroot_debug. The individual debug heap implementations are now exposed via a structure of function pointers and a common frontend dispatches the malloc and malloc_debug APIs through them. The MALLOC_DEBUG environment variable can be used to select the guarded heap by adding 'g', otherwise the debug heap is used as the default. Consequently the separate libroot_guarded is not needed anymore and has been removed. To allow the use of environment variables this early, init_env_post_heap has been added and the heap dependent atfork() moved there. This allowed to fold the code of init_heap_post_env into init_heap so the former has been removed. --- build/jam/packages/HaikuDevel | 1 - headers/private/libroot/libroot_private.h | 2 +- src/bin/leak_analyser.sh | 2 +- src/system/libroot/Jamfile | 26 -- src/system/libroot/libroot_init.c | 4 +- .../libroot/posix/malloc/arch-specific.cpp | 7 - src/system/libroot/posix/malloc_debug/Jamfile | 5 +- .../posix/malloc_debug/guarded_heap.cpp | 191 ++++-------- .../libroot/posix/malloc_debug/heap.cpp | 211 +++++-------- .../posix/malloc_debug/malloc_debug_api.cpp | 283 ++++++++++++++++++ .../posix/malloc_debug/malloc_debug_api.h | 57 ++++ src/system/libroot/posix/stdlib/env.cpp | 5 + src/system/libroot/stubbed/libroot_stubs.c | 2 +- .../libroot/stubbed/libroot_stubs_legacy.c | 2 +- 14 files changed, 477 insertions(+), 321 deletions(-) create mode 100644 src/system/libroot/posix/malloc_debug/malloc_debug_api.cpp create mode 100644 src/system/libroot/posix/malloc_debug/malloc_debug_api.h diff --git a/build/jam/packages/HaikuDevel b/build/jam/packages/HaikuDevel index b18f7d8b0a..de160cdb6f 100644 --- a/build/jam/packages/HaikuDevel +++ b/build/jam/packages/HaikuDevel @@ -21,7 +21,6 @@ AddFilesToPackage develop lib : kernel.so : _KERNEL_ ; # additional libraries local developmentLibs = libroot_debug.so - libroot_guarded.so ; AddFilesToPackage lib : $(developmentLibs) ; diff --git a/headers/private/libroot/libroot_private.h b/headers/private/libroot/libroot_private.h index 1d5fad3045..d0676a63ed 100644 --- a/headers/private/libroot/libroot_private.h +++ b/headers/private/libroot/libroot_private.h @@ -33,8 +33,8 @@ status_t __flatten_process_args(const char* const* args, int32 argCount, char*** _flatArgs, size_t* _flatSize); void _call_atexit_hooks_for_range(addr_t start, addr_t size); void __init_env(const struct user_space_program_args *args); +void __init_env_post_heap(void); status_t __init_heap(void); -void __init_heap_post_env(void); void __heap_terminate_after(void); void __init_time(addr_t commPageTable); diff --git a/src/bin/leak_analyser.sh b/src/bin/leak_analyser.sh index 222388ee02..66c6880ae0 100755 --- a/src/bin/leak_analyser.sh +++ b/src/bin/leak_analyser.sh @@ -14,7 +14,7 @@ then To generate such a file run a program with the following environment variables prefixed and pipe the output to a file: - LD_PRELOAD=libroot_guarded.so MALLOC_DEBUG=es50 program > file + LD_PRELOAD=libroot_debug.so MALLOC_DEBUG=ges50 program > file The number after the "s" is the stack trace depth. Note that there is an implementation defined maximum. diff --git a/src/system/libroot/Jamfile b/src/system/libroot/Jamfile index 1b29fb53c7..b9d962207f 100644 --- a/src/system/libroot/Jamfile +++ b/src/system/libroot/Jamfile @@ -63,11 +63,6 @@ for architectureObject in [ MultiArchSubDirSetup ] { ; librootDebugObjects = $(librootDebugObjects:G=$(architecture)) ; - local librootGuardedObjects = - posix_malloc_guarded.o - ; - librootGuardedObjects = $(librootGuardedObjects:G=$(architecture)) ; - local librootNoDebugObjects = posix_malloc.o ; @@ -75,15 +70,12 @@ for architectureObject in [ MultiArchSubDirSetup ] { local libroot = [ MultiArchDefaultGristFiles libroot.so ] ; local librootDebug = $(libroot:B=libroot_debug) ; - local librootGuarded = $(libroot:B=libroot_guarded) ; DONT_LINK_AGAINST_LIBROOT on $(libroot) = true ; DONT_LINK_AGAINST_LIBROOT on $(librootDebug) = true ; - DONT_LINK_AGAINST_LIBROOT on $(librootGuarded) = true ; SetVersionScript $(libroot) : libroot_versions ; SetVersionScript $(librootDebug) : libroot_versions ; - SetVersionScript $(librootGuarded) : libroot_versions ; SharedLibrary $(libroot) : @@ -109,18 +101,6 @@ for architectureObject in [ MultiArchSubDirSetup ] { [ TargetLibgcc ] ; - HAIKU_SONAME on $(librootGuarded) = libroot.so ; - - SharedLibrary $(librootGuarded) - : - libroot_init.c - : - $(librootObjects) - $(librootGuardedObjects) - [ TargetStaticLibsupc++ ] - [ TargetLibgcc ] - ; - # Copy libroot.so and update the copy's revision section. We link # everything against the original, but the copy will end up on the disk # image (this way we avoid unnecessary dependencies). The copy will be @@ -132,18 +112,12 @@ for architectureObject in [ MultiArchSubDirSetup ] { libroot.so : revisioned ] ; local revisionedLibrootDebug = $(librootDebug:G=$(revisionedLibroot:G)) ; - local revisionedLibrootGuarded - = $(librootGuarded:G=$(revisionedLibroot:G)) ; MakeLocate $(revisionedLibroot) : $(targetDir) ; CopySetHaikuRevision $(revisionedLibroot) : $(libroot) ; MakeLocate $(revisionedLibrootDebug) : $(targetDir) ; CopySetHaikuRevision $(revisionedLibrootDebug) : $(librootDebug) ; - - MakeLocate $(revisionedLibrootGuarded) : $(targetDir) ; - CopySetHaikuRevision $(revisionedLibrootGuarded) - : $(librootGuarded) ; } } } diff --git a/src/system/libroot/libroot_init.c b/src/system/libroot/libroot_init.c index 03cb17f70d..893833eea7 100644 --- a/src/system/libroot/libroot_init.c +++ b/src/system/libroot/libroot_init.c @@ -77,9 +77,9 @@ initialize_before(image_id imageID) __gCPUCount = info.cpu_count; __init_time((addr_t)__gCommPageAddress); - __init_heap(); __init_env(__gRuntimeLoader->program_args); - __init_heap_post_env(); + __init_heap(); + __init_env_post_heap(); __init_pwd_backend(); __set_stack_protection(); } diff --git a/src/system/libroot/posix/malloc/arch-specific.cpp b/src/system/libroot/posix/malloc/arch-specific.cpp index d2c25b8f5e..872867c38c 100644 --- a/src/system/libroot/posix/malloc/arch-specific.cpp +++ b/src/system/libroot/posix/malloc/arch-specific.cpp @@ -124,13 +124,6 @@ __init_heap(void) } -extern "C" void -__init_heap_post_env(void) -{ - // no heap options available -} - - extern "C" void __heap_terminate_after() { diff --git a/src/system/libroot/posix/malloc_debug/Jamfile b/src/system/libroot/posix/malloc_debug/Jamfile index 98d3b0bc58..0a2213d12f 100644 --- a/src/system/libroot/posix/malloc_debug/Jamfile +++ b/src/system/libroot/posix/malloc_debug/Jamfile @@ -15,10 +15,9 @@ for architectureObject in [ MultiArchSubDirSetup ] { MergeObject <$(architecture)>posix_malloc_debug.o : heap.cpp - ; - - MergeObject <$(architecture)>posix_malloc_guarded.o : guarded_heap.cpp + + malloc_debug_api.cpp ; } } diff --git a/src/system/libroot/posix/malloc_debug/guarded_heap.cpp b/src/system/libroot/posix/malloc_debug/guarded_heap.cpp index bc5e17a429..f8d2c7c27a 100644 --- a/src/system/libroot/posix/malloc_debug/guarded_heap.cpp +++ b/src/system/libroot/posix/malloc_debug/guarded_heap.cpp @@ -3,6 +3,8 @@ * Distributed under the terms of the MIT License. */ +#include "malloc_debug_api.h" + #include #include @@ -985,68 +987,36 @@ dump_allocations_full() // #pragma mark - Heap Debug API -extern "C" status_t -heap_debug_start_wall_checking(int msInterval) -{ - return B_NOT_SUPPORTED; -} - - -extern "C" status_t -heap_debug_stop_wall_checking() -{ - return B_NOT_SUPPORTED; -} - - -extern "C" void -heap_debug_set_paranoid_validation(bool enabled) -{ -} - - -extern "C" void -heap_debug_set_memory_reuse(bool enabled) +static void +guarded_heap_set_memory_reuse(bool enabled) { sGuardedHeap.reuse_memory = enabled; } -extern "C" void -heap_debug_set_debugger_calls(bool enabled) +static void +guarded_heap_set_debugger_calls(bool enabled) { sDebuggerCalls = enabled; } -extern "C" void -heap_debug_set_default_alignment(size_t defaultAlignment) +static void +guarded_heap_set_default_alignment(size_t defaultAlignment) { sDefaultAlignment = defaultAlignment; } -extern "C" void -heap_debug_validate_heaps() -{ -} - - -extern "C" void -heap_debug_validate_walls() -{ -} - - -extern "C" void -heap_debug_dump_allocations(bool statsOnly, thread_id thread) +static void +guarded_heap_dump_allocations(bool statsOnly, thread_id thread) { dump_allocations(sGuardedHeap, statsOnly, thread); } -extern "C" void -heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) +static void +guarded_heap_dump_heaps(bool dumpAreas, bool dumpBins) { WriteLocker heapLocker(sGuardedHeap.lock); dump_guarded_heap(sGuardedHeap); @@ -1070,31 +1040,16 @@ heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) } -extern "C" void * -heap_debug_malloc_with_guard_page(size_t size) -{ - return malloc(size); -} - - -extern "C" status_t -heap_debug_get_allocation_info(void *address, size_t *size, - thread_id *thread) -{ - return B_NOT_SUPPORTED; -} - - -extern "C" status_t -heap_debug_dump_allocations_on_exit(bool enabled) +static status_t +guarded_heap_set_dump_allocations_on_exit(bool enabled) { sDumpAllocationsOnExit = enabled; return B_OK; } -extern "C" status_t -heap_debug_set_stack_trace_depth(size_t stackTraceDepth) +static status_t +guarded_heap_set_stack_trace_depth(size_t stackTraceDepth) { if (stackTraceDepth == 0) { sStackTraceDepth = 0; @@ -1139,8 +1094,8 @@ init_after_fork() } -extern "C" status_t -__init_heap(void) +static status_t +guarded_heap_init(void) { if (!guarded_heap_area_create(sGuardedHeap, GUARDED_HEAP_INITIAL_SIZE)) return B_ERROR; @@ -1164,35 +1119,8 @@ __init_heap(void) } -extern "C" void -__init_heap_post_env(void) -{ - const char *mode = getenv("MALLOC_DEBUG"); - if (mode != NULL) { - if (strchr(mode, 'r')) - heap_debug_set_memory_reuse(false); - if (strchr(mode, 'e')) - heap_debug_dump_allocations_on_exit(true); - - size_t defaultAlignment = 0; - const char *argument = strchr(mode, 'a'); - if (argument != NULL - && sscanf(argument, "a%" B_SCNuSIZE, &defaultAlignment) == 1) { - heap_debug_set_default_alignment(defaultAlignment); - } - - size_t stackTraceDepth = 0; - argument = strchr(mode, 's'); - if (argument != NULL - && sscanf(argument, "s%" B_SCNuSIZE, &stackTraceDepth) == 1) { - heap_debug_set_stack_trace_depth(stackTraceDepth); - } - } -} - - -extern "C" void -__heap_terminate_after() +static void +guarded_heap_terminate_after() { if (sDumpAllocationsOnExit) dump_allocations_full(); @@ -1202,17 +1130,8 @@ __heap_terminate_after() // #pragma mark - Public API -extern "C" void* -sbrk_hook(long) -{ - debug_printf("sbrk not supported on malloc debug\n"); - panic("sbrk not supported on malloc debug\n"); - return NULL; -} - - -extern "C" void* -memalign(size_t alignment, size_t size) +static void* +heap_memalign(size_t alignment, size_t size) { if (size == 0) size = 1; @@ -1221,23 +1140,23 @@ memalign(size_t alignment, size_t size) } -extern "C" void* -malloc(size_t size) +static void* +heap_malloc(size_t size) { - return memalign(sDefaultAlignment, size); + return heap_memalign(sDefaultAlignment, size); } -extern "C" void -free(void* address) +static void +heap_free(void* address) { if (!guarded_heap_free(address)) panic("free failed for address %p", address); } -extern "C" void* -realloc(void* address, size_t newSize) +static void* +heap_realloc(void* address, size_t newSize) { if (newSize == 0) { free(address); @@ -1245,40 +1164,42 @@ realloc(void* address, size_t newSize) } if (address == NULL) - return memalign(sDefaultAlignment, newSize); + return heap_memalign(sDefaultAlignment, newSize); return guarded_heap_realloc(address, newSize); } -extern "C" void* -calloc(size_t numElements, size_t size) -{ - void* address = malloc(numElements * size); - if (address != NULL) - memset(address, 0, numElements * size); +heap_implementation __mallocGuardedHeap = { + guarded_heap_init, + guarded_heap_terminate_after, - return address; -} + heap_memalign, + heap_malloc, + heap_free, + heap_realloc, + NULL, // calloc + NULL, // valloc + NULL, // posix_memalign -extern "C" void* -valloc(size_t size) -{ - return memalign(B_PAGE_SIZE, size); -} + NULL, // start_wall_checking + NULL, // stop_wall_checking + NULL, // set_paranoid_validation + guarded_heap_set_memory_reuse, + guarded_heap_set_debugger_calls, + guarded_heap_set_default_alignment, -extern "C" int -posix_memalign(void **pointer, size_t alignment, size_t size) -{ - // this cryptic line accepts zero and all powers of two - if (((~alignment + 1) | ((alignment << 1) - 1)) != ~0UL) - return EINVAL; + NULL, // validate_heaps + NULL, // validate_walls - *pointer = memalign(alignment, size); - if (*pointer == NULL) - return ENOMEM; + guarded_heap_dump_allocations, + guarded_heap_dump_heaps, + heap_malloc, - return 0; -} + NULL, // get_allocation_info + + guarded_heap_set_dump_allocations_on_exit, + guarded_heap_set_stack_trace_depth +}; diff --git a/src/system/libroot/posix/malloc_debug/heap.cpp b/src/system/libroot/posix/malloc_debug/heap.cpp index 10745f39d0..096fd699b2 100644 --- a/src/system/libroot/posix/malloc_debug/heap.cpp +++ b/src/system/libroot/posix/malloc_debug/heap.cpp @@ -10,8 +10,9 @@ */ +#include "malloc_debug_api.h" + #include -#include #include #include #include @@ -38,6 +39,9 @@ #define ASSERT(x) if (!(x)) panic("assert failed: %s", #x); +static void *debug_heap_memalign(size_t alignment, size_t size); + + static bool sDebuggerCalls = true; static bool sReuseMemory = true; static bool sParanoidValidation = false; @@ -773,7 +777,7 @@ heap_remove_area(heap_allocator *heap, heap_area *area) } -heap_allocator * +static heap_allocator * heap_create_allocator(const char *name, addr_t base, size_t size, const heap_class *heapClass) { @@ -1103,15 +1107,7 @@ heap_allocate_from_bin(heap_allocator *heap, uint32 binIndex, size_t size) } -static bool -is_valid_alignment(size_t number) -{ - // this cryptic line accepts zero and all powers of two - return ((~number + 1) | ((number << 1) - 1)) == ~0UL; -} - - -void * +static void * heap_memalign(heap_allocator *heap, size_t alignment, size_t size) { INFO(("memalign(alignment = %lu, size = %lu)\n", alignment, size)); @@ -1172,7 +1168,7 @@ heap_memalign(heap_allocator *heap, size_t alignment, size_t size) } -status_t +static status_t heap_free(heap_allocator *heap, void *address) { if (address == NULL) @@ -1473,7 +1469,7 @@ heap_realloc(heap_allocator *heap, void *address, void **newAddress, newSize -= sizeof(addr_t) + sizeof(heap_leak_check_info); // if not, allocate a new chunk of memory - *newAddress = memalign(sDefaultAlignment, newSize); + *newAddress = debug_heap_memalign(sDefaultAlignment, newSize); if (*newAddress == NULL) { // we tried but it didn't work out, but still the operation is done return B_OK; @@ -1643,8 +1639,8 @@ heap_wall_checker(void *data) // #pragma mark - Heap Debug API -extern "C" status_t -heap_debug_start_wall_checking(int msInterval) +static status_t +debug_heap_start_wall_checking(int msInterval) { if (sWallCheckThread < 0) { sWallCheckThread = spawn_thread(heap_wall_checker, "heap wall checker", @@ -1659,8 +1655,8 @@ heap_debug_start_wall_checking(int msInterval) } -extern "C" status_t -heap_debug_stop_wall_checking() +static status_t +debug_heap_stop_wall_checking() { int32 result; sStopWallChecking = true; @@ -1668,66 +1664,52 @@ heap_debug_stop_wall_checking() } -extern "C" void -heap_debug_set_paranoid_validation(bool enabled) +static void +debug_heap_set_paranoid_validation(bool enabled) { sParanoidValidation = enabled; } -extern "C" void -heap_debug_set_memory_reuse(bool enabled) +static void +debug_heap_set_memory_reuse(bool enabled) { sReuseMemory = enabled; } -extern "C" void -heap_debug_set_debugger_calls(bool enabled) +static void +debug_heap_set_debugger_calls(bool enabled) { sDebuggerCalls = enabled; } -extern "C" void -heap_debug_set_default_alignment(size_t defaultAlignment) +static void +debug_heap_set_default_alignment(size_t defaultAlignment) { sDefaultAlignment = defaultAlignment; } -extern "C" void -heap_debug_validate_heaps() +static void +debug_heap_validate_heaps() { for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) heap_validate_heap(sHeaps[i]); } -extern "C" void -heap_debug_validate_walls() -{ - heap_validate_walls(); -} - - -extern "C" void -heap_debug_dump_allocations(bool statsOnly, thread_id thread) -{ - dump_allocations(statsOnly, thread); -} - - -extern "C" void -heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) +static void +debug_heap_dump_heaps(bool dumpAreas, bool dumpBins) { for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) dump_allocator(sHeaps[i], dumpAreas, dumpBins); } -extern "C" void * -heap_debug_malloc_with_guard_page(size_t size) +static void * +debug_heap_malloc_with_guard_page(size_t size) { size_t areaSize = ROUNDUP(size + sizeof(area_allocation_info) + B_PAGE_SIZE, B_PAGE_SIZE); @@ -1775,8 +1757,8 @@ heap_debug_malloc_with_guard_page(size_t size) } -extern "C" status_t -heap_debug_get_allocation_info(void *address, size_t *size, +static status_t +debug_heap_get_allocation_info(void *address, size_t *size, thread_id *thread) { for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) { @@ -1807,25 +1789,11 @@ heap_debug_get_allocation_info(void *address, size_t *size, } -extern "C" status_t -heap_debug_dump_allocations_on_exit(bool enabled) -{ - return B_NOT_SUPPORTED; -} - - -extern "C" status_t -heap_debug_set_stack_trace_depth(size_t stackTraceDepth) -{ - return B_NOT_SUPPORTED; -} - - // #pragma mark - Init -extern "C" status_t -__init_heap(void) +static status_t +debug_heap_init(void) { // This will locate the heap base at 384 MB and reserve the next 1152 MB // for it. They may get reclaimed by other areas, though, but the maximum @@ -1853,53 +1821,11 @@ __init_heap(void) } -extern "C" void -__init_heap_post_env(void) -{ - const char *mode = getenv("MALLOC_DEBUG"); - if (mode != NULL) { - if (strchr(mode, 'p')) - heap_debug_set_paranoid_validation(true); - if (strchr(mode, 'w')) - heap_debug_start_wall_checking(500); - else if (strchr(mode, 'W')) - heap_debug_start_wall_checking(100); - if (strchr(mode, 'g')) - sUseGuardPage = true; - if (strchr(mode, 'r')) - heap_debug_set_memory_reuse(false); - - size_t defaultAlignment = 0; - const char *argument = strchr(mode, 'a'); - if (argument != NULL - && sscanf(argument, "a%" B_SCNuSIZE, &defaultAlignment) == 1) { - heap_debug_set_default_alignment(defaultAlignment); - } - } -} - - -extern "C" void -__heap_terminate_after() -{ - // nothing to do -} - - // #pragma mark - Public API -extern "C" void * -sbrk_hook(long) -{ - debug_printf("sbrk not supported on malloc debug\n"); - panic("sbrk not supported on malloc debug\n"); - return NULL; -} - - -void * -memalign(size_t alignment, size_t size) +static void * +debug_heap_memalign(size_t alignment, size_t size) { size_t alignedSize = size + sizeof(addr_t) + sizeof(heap_leak_check_info); if (alignment != 0 && alignment < B_PAGE_SIZE) @@ -1974,18 +1900,18 @@ memalign(size_t alignment, size_t size) } -void * -malloc(size_t size) +static void * +debug_heap_malloc(size_t size) { if (sUseGuardPage) - return heap_debug_malloc_with_guard_page(size); + return debug_heap_malloc_with_guard_page(size); - return memalign(sDefaultAlignment, size); + return debug_heap_memalign(sDefaultAlignment, size); } -void -free(void *address) +static void +debug_heap_free(void *address) { for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) { heap_allocator *heap = sHeaps[i]; @@ -2017,11 +1943,11 @@ free(void *address) } -void * -realloc(void *address, size_t newSize) +static void * +debug_heap_realloc(void *address, size_t newSize) { if (address == NULL) - return memalign(sDefaultAlignment, newSize); + return debug_heap_memalign(sDefaultAlignment, newSize); if (newSize == 0) { free(address); @@ -2079,7 +2005,7 @@ realloc(void *address, size_t newSize) } // have to allocate/copy/free - TODO maybe resize the area instead? - newAddress = malloc(newSize); + newAddress = debug_heap_memalign(sDefaultAlignment, newSize); if (newAddress == NULL) { panic("realloc(): failed to allocate new block of %ld" " bytes\n", newSize); @@ -2100,33 +2026,32 @@ realloc(void *address, size_t newSize) } -void * -calloc(size_t numElements, size_t size) -{ - void *address = malloc(numElements * size); - if (address != NULL) - memset(address, 0, numElements * size); +heap_implementation __mallocDebugHeap = { + debug_heap_init, + NULL, // terminate_after - return address; -} + debug_heap_memalign, + debug_heap_malloc, + debug_heap_free, + debug_heap_realloc, + NULL, // calloc + NULL, // valloc + NULL, // posix_memalign -extern "C" void * -valloc(size_t size) -{ - return memalign(B_PAGE_SIZE, size); -} + debug_heap_start_wall_checking, + debug_heap_stop_wall_checking, + debug_heap_set_paranoid_validation, + debug_heap_set_memory_reuse, + debug_heap_set_debugger_calls, + debug_heap_set_default_alignment, + debug_heap_validate_heaps, + heap_validate_walls, + dump_allocations, + debug_heap_dump_heaps, + debug_heap_malloc_with_guard_page, + debug_heap_get_allocation_info, - -extern "C" int -posix_memalign(void **pointer, size_t alignment, size_t size) -{ - if (!is_valid_alignment(alignment)) - return EINVAL; - - *pointer = memalign(alignment, size); - if (*pointer == NULL) - return ENOMEM; - - return 0; -} + NULL, // set_dump_allocations_on_exit + NULL // set_stack_trace_depth +}; diff --git a/src/system/libroot/posix/malloc_debug/malloc_debug_api.cpp b/src/system/libroot/posix/malloc_debug/malloc_debug_api.cpp new file mode 100644 index 0000000000..45d3c1c6c3 --- /dev/null +++ b/src/system/libroot/posix/malloc_debug/malloc_debug_api.cpp @@ -0,0 +1,283 @@ +/* + * Copyright 2015, Michael Lotz . + * Distributed under the terms of the MIT License. + */ + + +#include "malloc_debug_api.h" + +#include +#include + +#include +#include + + +static heap_implementation* sCurrentHeap = NULL; + + +// #pragma mark - Heap Debug API + + +extern "C" status_t +heap_debug_start_wall_checking(int msInterval) +{ + if (sCurrentHeap->start_wall_checking != NULL) + return sCurrentHeap->start_wall_checking(msInterval); + + return B_NOT_SUPPORTED; +} + + +extern "C" status_t +heap_debug_stop_wall_checking() +{ + if (sCurrentHeap->stop_wall_checking != NULL) + return sCurrentHeap->stop_wall_checking(); + + return B_NOT_SUPPORTED; +} + + +extern "C" void +heap_debug_set_paranoid_validation(bool enabled) +{ + if (sCurrentHeap->set_paranoid_validation != NULL) + sCurrentHeap->set_paranoid_validation(enabled); +} + + +extern "C" void +heap_debug_set_memory_reuse(bool enabled) +{ + if (sCurrentHeap->set_memory_reuse != NULL) + sCurrentHeap->set_memory_reuse(enabled); +} + + +extern "C" void +heap_debug_set_debugger_calls(bool enabled) +{ + if (sCurrentHeap->set_debugger_calls != NULL) + sCurrentHeap->set_debugger_calls(enabled); +} + + +extern "C" void +heap_debug_set_default_alignment(size_t defaultAlignment) +{ + if (sCurrentHeap->set_default_alignment != NULL) + sCurrentHeap->set_default_alignment(defaultAlignment); +} + + +extern "C" void +heap_debug_validate_heaps() +{ + if (sCurrentHeap->validate_heaps != NULL) + sCurrentHeap->validate_heaps(); +} + + +extern "C" void +heap_debug_validate_walls() +{ + if (sCurrentHeap->validate_walls != NULL) + sCurrentHeap->validate_walls(); +} + + +extern "C" void +heap_debug_dump_allocations(bool statsOnly, thread_id thread) +{ + if (sCurrentHeap->dump_allocations != NULL) + sCurrentHeap->dump_allocations(statsOnly, thread); +} + + +extern "C" void +heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) +{ + if (sCurrentHeap->dump_heaps != NULL) + sCurrentHeap->dump_heaps(dumpAreas, dumpBins); +} + + +extern "C" void * +heap_debug_malloc_with_guard_page(size_t size) +{ + if (sCurrentHeap->malloc_with_guard_page != NULL) + return sCurrentHeap->malloc_with_guard_page(size); + + return NULL; +} + + +extern "C" status_t +heap_debug_get_allocation_info(void *address, size_t *size, + thread_id *thread) +{ + if (sCurrentHeap->get_allocation_info != NULL) + return sCurrentHeap->get_allocation_info(address, size, thread); + + return B_NOT_SUPPORTED; +} + + +extern "C" status_t +heap_debug_set_dump_allocations_on_exit(bool enabled) +{ + if (sCurrentHeap->set_dump_allocations_on_exit != NULL) + return sCurrentHeap->set_dump_allocations_on_exit(enabled); + + return B_NOT_SUPPORTED; +} + + +extern "C" status_t +heap_debug_set_stack_trace_depth(size_t stackTraceDepth) +{ + if (sCurrentHeap->set_stack_trace_depth != NULL) + return sCurrentHeap->set_stack_trace_depth(stackTraceDepth); + + return B_NOT_SUPPORTED; +} + + +// #pragma mark - Init + + +extern "C" status_t +__init_heap(void) +{ + const char *mode = getenv("MALLOC_DEBUG"); + if (mode == NULL || strchr(mode, 'g') == NULL) + sCurrentHeap = &__mallocDebugHeap; + else + sCurrentHeap = &__mallocGuardedHeap; + + status_t result = sCurrentHeap->init(); + if (result != B_OK) + return result; + + if (mode != NULL) { + if (strchr(mode, 'p') != NULL) + heap_debug_set_paranoid_validation(true); + if (strchr(mode, 'r') != NULL) + heap_debug_set_memory_reuse(false); + if (strchr(mode, 'e') != NULL) + heap_debug_set_dump_allocations_on_exit(true); + + size_t defaultAlignment = 0; + const char *argument = strchr(mode, 'a'); + if (argument != NULL + && sscanf(argument, "a%" B_SCNuSIZE, &defaultAlignment) == 1) { + heap_debug_set_default_alignment(defaultAlignment); + } + + size_t stackTraceDepth = 0; + argument = strchr(mode, 's'); + if (argument != NULL + && sscanf(argument, "s%" B_SCNuSIZE, &stackTraceDepth) == 1) { + heap_debug_set_stack_trace_depth(stackTraceDepth); + } + + int wallCheckInterval = 0; + argument = strchr(mode, 'w'); + if (argument != NULL + && sscanf(argument, "w%d", &wallCheckInterval) == 1) { + heap_debug_start_wall_checking(wallCheckInterval); + } + } + + return B_OK; +} + + +extern "C" void +__heap_terminate_after() +{ + if (sCurrentHeap->terminate_after != NULL) + sCurrentHeap->terminate_after(); +} + + +// #pragma mark - Public API + + +extern "C" void* +sbrk_hook(long) +{ + debug_printf("sbrk not supported on malloc debug\n"); + debugger("sbrk not supported on malloc debug"); + return NULL; +} + + +extern "C" void* +memalign(size_t alignment, size_t size) +{ + return sCurrentHeap->memalign(alignment, size); +} + + +extern "C" void* +malloc(size_t size) +{ + return sCurrentHeap->malloc(size); +} + + +extern "C" void +free(void* address) +{ + sCurrentHeap->free(address); +} + + +extern "C" void* +realloc(void* address, size_t newSize) +{ + return sCurrentHeap->realloc(address, newSize); +} + + +extern "C" void* +calloc(size_t numElements, size_t size) +{ + if (sCurrentHeap->calloc != NULL) + return sCurrentHeap->calloc(numElements, size); + + void* address = malloc(numElements * size); + if (address != NULL) + memset(address, 0, numElements * size); + + return address; +} + + +extern "C" void* +valloc(size_t size) +{ + if (sCurrentHeap->valloc != NULL) + return sCurrentHeap->valloc(size); + + return memalign(B_PAGE_SIZE, size); +} + + +extern "C" int +posix_memalign(void **pointer, size_t alignment, size_t size) +{ + if (sCurrentHeap->posix_memalign != NULL) + return sCurrentHeap->posix_memalign(pointer, alignment, size); + + if (!is_valid_alignment(alignment)) + return EINVAL; + + *pointer = memalign(alignment, size); + if (*pointer == NULL) + return ENOMEM; + + return 0; +} diff --git a/src/system/libroot/posix/malloc_debug/malloc_debug_api.h b/src/system/libroot/posix/malloc_debug/malloc_debug_api.h new file mode 100644 index 0000000000..dc949a9dd9 --- /dev/null +++ b/src/system/libroot/posix/malloc_debug/malloc_debug_api.h @@ -0,0 +1,57 @@ +/* + * Copyright 2015, Michael Lotz . + * Distributed under the terms of the MIT License. + */ +#ifndef MALLOC_DEBUG_API_H +#define MALLOC_DEBUG_API_H + +#include + + +struct heap_implementation { + status_t (*init)(); + void (*terminate_after)(); + + // Mandatory hooks + void* (*memalign)(size_t alignment, size_t size); + void* (*malloc)(size_t size); + void (*free)(void* address); + void* (*realloc)(void* address, size_t newSize); + + // Hooks with default implementations + void* (*calloc)(size_t numElements, size_t size); + void* (*valloc)(size_t size); + int (*posix_memalign)(void** pointer, size_t alignment, + size_t size); + + // Heap Debug API + status_t (*start_wall_checking)(int msInterval); + status_t (*stop_wall_checking)(); + void (*set_paranoid_validation)(bool enabled); + void (*set_memory_reuse)(bool enabled); + void (*set_debugger_calls)(bool enabled); + void (*set_default_alignment)(size_t defaultAlignment); + void (*validate_heaps)(); + void (*validate_walls)(); + void (*dump_allocations)(bool statsOnly, thread_id thread); + void (*dump_heaps)(bool dumpAreas, bool dumpBins); + void* (*malloc_with_guard_page)(size_t size); + status_t (*get_allocation_info)(void* address, size_t *size, + thread_id *thread); + status_t (*set_dump_allocations_on_exit)(bool enabled); + status_t (*set_stack_trace_depth)(size_t stackTraceDepth); +}; + + +extern heap_implementation __mallocDebugHeap; +extern heap_implementation __mallocGuardedHeap; + + +static inline bool +is_valid_alignment(size_t number) +{ + // this cryptic line accepts zero and all powers of two + return ((~number + 1) | ((number << 1) - 1)) == ~0UL; +} + +#endif // MALLOC_DEBUG_API_H diff --git a/src/system/libroot/posix/stdlib/env.cpp b/src/system/libroot/posix/stdlib/env.cpp index 578a25506b..e811eeb6f5 100644 --- a/src/system/libroot/posix/stdlib/env.cpp +++ b/src/system/libroot/posix/stdlib/env.cpp @@ -205,7 +205,12 @@ __init_env(const struct user_space_program_args *args) // protect our implementation environ = args->env; sManagedEnviron = NULL; +} + +void +__init_env_post_heap() +{ atfork(environ_fork_hook); } diff --git a/src/system/libroot/stubbed/libroot_stubs.c b/src/system/libroot/stubbed/libroot_stubs.c index 961185532f..cd8ff77e4c 100644 --- a/src/system/libroot/stubbed/libroot_stubs.c +++ b/src/system/libroot/stubbed/libroot_stubs.c @@ -892,8 +892,8 @@ void __ilogb() {} void __ilogbf() {} void __ilogbl() {} void __init_env() {} +void __init_env_post_heap() {} void __init_heap() {} -void __init_heap_post_env() {} void __init_once() {} void __init_pthread() {} void __init_pwd_backend() {} diff --git a/src/system/libroot/stubbed/libroot_stubs_legacy.c b/src/system/libroot/stubbed/libroot_stubs_legacy.c index 2d72b862d0..855c3bbad2 100644 --- a/src/system/libroot/stubbed/libroot_stubs_legacy.c +++ b/src/system/libroot/stubbed/libroot_stubs_legacy.c @@ -726,8 +726,8 @@ void __ilogb() {} void __ilogbf() {} void __ilogbl() {} void __init_env() {} +void __init_env_post_heap() {} void __init_heap() {} -void __init_heap_post_env() {} void __init_once() {} void __init_pthread() {} void __init_pwd_backend() {}