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.
This commit is contained in:
Michael Lotz
2015-08-13 22:12:18 +02:00
parent 7492419877
commit f474606ee9
14 changed files with 477 additions and 321 deletions
-1
View File
@@ -21,7 +21,6 @@ AddFilesToPackage develop lib : kernel.so : _KERNEL_ ;
# additional libraries # additional libraries
local developmentLibs = local developmentLibs =
<revisioned>libroot_debug.so <revisioned>libroot_debug.so
<revisioned>libroot_guarded.so
; ;
AddFilesToPackage lib : $(developmentLibs) ; AddFilesToPackage lib : $(developmentLibs) ;
+1 -1
View File
@@ -33,8 +33,8 @@ status_t __flatten_process_args(const char* const* args, int32 argCount,
char*** _flatArgs, size_t* _flatSize); char*** _flatArgs, size_t* _flatSize);
void _call_atexit_hooks_for_range(addr_t start, addr_t size); 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(const struct user_space_program_args *args);
void __init_env_post_heap(void);
status_t __init_heap(void); status_t __init_heap(void);
void __init_heap_post_env(void);
void __heap_terminate_after(void); void __heap_terminate_after(void);
void __init_time(addr_t commPageTable); void __init_time(addr_t commPageTable);
+1 -1
View File
@@ -14,7 +14,7 @@ then
To generate such a file run a program with the following To generate such a file run a program with the following
environment variables prefixed and pipe the output to a file: 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 The number after the "s" is the stack trace depth. Note that
there is an implementation defined maximum. there is an implementation defined maximum.
-26
View File
@@ -63,11 +63,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
; ;
librootDebugObjects = $(librootDebugObjects:G=$(architecture)) ; librootDebugObjects = $(librootDebugObjects:G=$(architecture)) ;
local librootGuardedObjects =
posix_malloc_guarded.o
;
librootGuardedObjects = $(librootGuardedObjects:G=$(architecture)) ;
local librootNoDebugObjects = local librootNoDebugObjects =
posix_malloc.o posix_malloc.o
; ;
@@ -75,15 +70,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
local libroot = [ MultiArchDefaultGristFiles libroot.so ] ; local libroot = [ MultiArchDefaultGristFiles libroot.so ] ;
local librootDebug = $(libroot:B=libroot_debug) ; local librootDebug = $(libroot:B=libroot_debug) ;
local librootGuarded = $(libroot:B=libroot_guarded) ;
DONT_LINK_AGAINST_LIBROOT on $(libroot) = true ; DONT_LINK_AGAINST_LIBROOT on $(libroot) = true ;
DONT_LINK_AGAINST_LIBROOT on $(librootDebug) = true ; DONT_LINK_AGAINST_LIBROOT on $(librootDebug) = true ;
DONT_LINK_AGAINST_LIBROOT on $(librootGuarded) = true ;
SetVersionScript $(libroot) : libroot_versions ; SetVersionScript $(libroot) : libroot_versions ;
SetVersionScript $(librootDebug) : libroot_versions ; SetVersionScript $(librootDebug) : libroot_versions ;
SetVersionScript $(librootGuarded) : libroot_versions ;
SharedLibrary $(libroot) SharedLibrary $(libroot)
: :
@@ -109,18 +101,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
[ TargetLibgcc ] [ 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 # 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 # everything against the original, but the copy will end up on the disk
# image (this way we avoid unnecessary dependencies). The copy will be # image (this way we avoid unnecessary dependencies). The copy will be
@@ -132,18 +112,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
libroot.so : revisioned ] ; libroot.so : revisioned ] ;
local revisionedLibrootDebug local revisionedLibrootDebug
= $(librootDebug:G=$(revisionedLibroot:G)) ; = $(librootDebug:G=$(revisionedLibroot:G)) ;
local revisionedLibrootGuarded
= $(librootGuarded:G=$(revisionedLibroot:G)) ;
MakeLocate $(revisionedLibroot) : $(targetDir) ; MakeLocate $(revisionedLibroot) : $(targetDir) ;
CopySetHaikuRevision $(revisionedLibroot) : $(libroot) ; CopySetHaikuRevision $(revisionedLibroot) : $(libroot) ;
MakeLocate $(revisionedLibrootDebug) : $(targetDir) ; MakeLocate $(revisionedLibrootDebug) : $(targetDir) ;
CopySetHaikuRevision $(revisionedLibrootDebug) : $(librootDebug) ; CopySetHaikuRevision $(revisionedLibrootDebug) : $(librootDebug) ;
MakeLocate $(revisionedLibrootGuarded) : $(targetDir) ;
CopySetHaikuRevision $(revisionedLibrootGuarded)
: $(librootGuarded) ;
} }
} }
} }
+2 -2
View File
@@ -77,9 +77,9 @@ initialize_before(image_id imageID)
__gCPUCount = info.cpu_count; __gCPUCount = info.cpu_count;
__init_time((addr_t)__gCommPageAddress); __init_time((addr_t)__gCommPageAddress);
__init_heap();
__init_env(__gRuntimeLoader->program_args); __init_env(__gRuntimeLoader->program_args);
__init_heap_post_env(); __init_heap();
__init_env_post_heap();
__init_pwd_backend(); __init_pwd_backend();
__set_stack_protection(); __set_stack_protection();
} }
@@ -124,13 +124,6 @@ __init_heap(void)
} }
extern "C" void
__init_heap_post_env(void)
{
// no heap options available
}
extern "C" void extern "C" void
__heap_terminate_after() __heap_terminate_after()
{ {
@@ -15,10 +15,9 @@ for architectureObject in [ MultiArchSubDirSetup ] {
MergeObject <$(architecture)>posix_malloc_debug.o : MergeObject <$(architecture)>posix_malloc_debug.o :
heap.cpp heap.cpp
;
MergeObject <$(architecture)>posix_malloc_guarded.o :
guarded_heap.cpp guarded_heap.cpp
malloc_debug_api.cpp
; ;
} }
} }
@@ -3,6 +3,8 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "malloc_debug_api.h"
#include <malloc.h> #include <malloc.h>
#include <stdio.h> #include <stdio.h>
@@ -985,68 +987,36 @@ dump_allocations_full()
// #pragma mark - Heap Debug API // #pragma mark - Heap Debug API
extern "C" status_t static void
heap_debug_start_wall_checking(int msInterval) guarded_heap_set_memory_reuse(bool enabled)
{
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)
{ {
sGuardedHeap.reuse_memory = enabled; sGuardedHeap.reuse_memory = enabled;
} }
extern "C" void static void
heap_debug_set_debugger_calls(bool enabled) guarded_heap_set_debugger_calls(bool enabled)
{ {
sDebuggerCalls = enabled; sDebuggerCalls = enabled;
} }
extern "C" void static void
heap_debug_set_default_alignment(size_t defaultAlignment) guarded_heap_set_default_alignment(size_t defaultAlignment)
{ {
sDefaultAlignment = defaultAlignment; sDefaultAlignment = defaultAlignment;
} }
extern "C" void static void
heap_debug_validate_heaps() guarded_heap_dump_allocations(bool statsOnly, thread_id thread)
{
}
extern "C" void
heap_debug_validate_walls()
{
}
extern "C" void
heap_debug_dump_allocations(bool statsOnly, thread_id thread)
{ {
dump_allocations(sGuardedHeap, statsOnly, thread); dump_allocations(sGuardedHeap, statsOnly, thread);
} }
extern "C" void static void
heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) guarded_heap_dump_heaps(bool dumpAreas, bool dumpBins)
{ {
WriteLocker heapLocker(sGuardedHeap.lock); WriteLocker heapLocker(sGuardedHeap.lock);
dump_guarded_heap(sGuardedHeap); dump_guarded_heap(sGuardedHeap);
@@ -1070,31 +1040,16 @@ heap_debug_dump_heaps(bool dumpAreas, bool dumpBins)
} }
extern "C" void * static status_t
heap_debug_malloc_with_guard_page(size_t size) guarded_heap_set_dump_allocations_on_exit(bool enabled)
{
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)
{ {
sDumpAllocationsOnExit = enabled; sDumpAllocationsOnExit = enabled;
return B_OK; return B_OK;
} }
extern "C" status_t static status_t
heap_debug_set_stack_trace_depth(size_t stackTraceDepth) guarded_heap_set_stack_trace_depth(size_t stackTraceDepth)
{ {
if (stackTraceDepth == 0) { if (stackTraceDepth == 0) {
sStackTraceDepth = 0; sStackTraceDepth = 0;
@@ -1139,8 +1094,8 @@ init_after_fork()
} }
extern "C" status_t static status_t
__init_heap(void) guarded_heap_init(void)
{ {
if (!guarded_heap_area_create(sGuardedHeap, GUARDED_HEAP_INITIAL_SIZE)) if (!guarded_heap_area_create(sGuardedHeap, GUARDED_HEAP_INITIAL_SIZE))
return B_ERROR; return B_ERROR;
@@ -1164,35 +1119,8 @@ __init_heap(void)
} }
extern "C" void static void
__init_heap_post_env(void) guarded_heap_terminate_after()
{
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()
{ {
if (sDumpAllocationsOnExit) if (sDumpAllocationsOnExit)
dump_allocations_full(); dump_allocations_full();
@@ -1202,17 +1130,8 @@ __heap_terminate_after()
// #pragma mark - Public API // #pragma mark - Public API
extern "C" void* static void*
sbrk_hook(long) heap_memalign(size_t alignment, size_t size)
{
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)
{ {
if (size == 0) if (size == 0)
size = 1; size = 1;
@@ -1221,23 +1140,23 @@ memalign(size_t alignment, size_t size)
} }
extern "C" void* static void*
malloc(size_t size) heap_malloc(size_t size)
{ {
return memalign(sDefaultAlignment, size); return heap_memalign(sDefaultAlignment, size);
} }
extern "C" void static void
free(void* address) heap_free(void* address)
{ {
if (!guarded_heap_free(address)) if (!guarded_heap_free(address))
panic("free failed for address %p", address); panic("free failed for address %p", address);
} }
extern "C" void* static void*
realloc(void* address, size_t newSize) heap_realloc(void* address, size_t newSize)
{ {
if (newSize == 0) { if (newSize == 0) {
free(address); free(address);
@@ -1245,40 +1164,42 @@ realloc(void* address, size_t newSize)
} }
if (address == NULL) if (address == NULL)
return memalign(sDefaultAlignment, newSize); return heap_memalign(sDefaultAlignment, newSize);
return guarded_heap_realloc(address, newSize); return guarded_heap_realloc(address, newSize);
} }
extern "C" void* heap_implementation __mallocGuardedHeap = {
calloc(size_t numElements, size_t size) guarded_heap_init,
{ guarded_heap_terminate_after,
void* address = malloc(numElements * size);
if (address != NULL)
memset(address, 0, numElements * size);
return address; heap_memalign,
} heap_malloc,
heap_free,
heap_realloc,
NULL, // calloc
NULL, // valloc
NULL, // posix_memalign
extern "C" void* NULL, // start_wall_checking
valloc(size_t size) NULL, // stop_wall_checking
{ NULL, // set_paranoid_validation
return memalign(B_PAGE_SIZE, size);
}
guarded_heap_set_memory_reuse,
guarded_heap_set_debugger_calls,
guarded_heap_set_default_alignment,
extern "C" int NULL, // validate_heaps
posix_memalign(void **pointer, size_t alignment, size_t size) NULL, // validate_walls
{
// this cryptic line accepts zero and all powers of two
if (((~alignment + 1) | ((alignment << 1) - 1)) != ~0UL)
return EINVAL;
*pointer = memalign(alignment, size); guarded_heap_dump_allocations,
if (*pointer == NULL) guarded_heap_dump_heaps,
return ENOMEM; heap_malloc,
return 0; NULL, // get_allocation_info
}
guarded_heap_set_dump_allocations_on_exit,
guarded_heap_set_stack_trace_depth
};
+68 -143
View File
@@ -10,8 +10,9 @@
*/ */
#include "malloc_debug_api.h"
#include <malloc.h> #include <malloc.h>
#include <malloc_debug.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -38,6 +39,9 @@
#define ASSERT(x) if (!(x)) panic("assert failed: %s", #x); #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 sDebuggerCalls = true;
static bool sReuseMemory = true; static bool sReuseMemory = true;
static bool sParanoidValidation = false; 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, heap_create_allocator(const char *name, addr_t base, size_t size,
const heap_class *heapClass) const heap_class *heapClass)
{ {
@@ -1103,15 +1107,7 @@ heap_allocate_from_bin(heap_allocator *heap, uint32 binIndex, size_t size)
} }
static bool static void *
is_valid_alignment(size_t number)
{
// this cryptic line accepts zero and all powers of two
return ((~number + 1) | ((number << 1) - 1)) == ~0UL;
}
void *
heap_memalign(heap_allocator *heap, size_t alignment, size_t size) heap_memalign(heap_allocator *heap, size_t alignment, size_t size)
{ {
INFO(("memalign(alignment = %lu, size = %lu)\n", alignment, 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) heap_free(heap_allocator *heap, void *address)
{ {
if (address == NULL) 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); newSize -= sizeof(addr_t) + sizeof(heap_leak_check_info);
// if not, allocate a new chunk of memory // if not, allocate a new chunk of memory
*newAddress = memalign(sDefaultAlignment, newSize); *newAddress = debug_heap_memalign(sDefaultAlignment, newSize);
if (*newAddress == NULL) { if (*newAddress == NULL) {
// we tried but it didn't work out, but still the operation is done // we tried but it didn't work out, but still the operation is done
return B_OK; return B_OK;
@@ -1643,8 +1639,8 @@ heap_wall_checker(void *data)
// #pragma mark - Heap Debug API // #pragma mark - Heap Debug API
extern "C" status_t static status_t
heap_debug_start_wall_checking(int msInterval) debug_heap_start_wall_checking(int msInterval)
{ {
if (sWallCheckThread < 0) { if (sWallCheckThread < 0) {
sWallCheckThread = spawn_thread(heap_wall_checker, "heap wall checker", sWallCheckThread = spawn_thread(heap_wall_checker, "heap wall checker",
@@ -1659,8 +1655,8 @@ heap_debug_start_wall_checking(int msInterval)
} }
extern "C" status_t static status_t
heap_debug_stop_wall_checking() debug_heap_stop_wall_checking()
{ {
int32 result; int32 result;
sStopWallChecking = true; sStopWallChecking = true;
@@ -1668,66 +1664,52 @@ heap_debug_stop_wall_checking()
} }
extern "C" void static void
heap_debug_set_paranoid_validation(bool enabled) debug_heap_set_paranoid_validation(bool enabled)
{ {
sParanoidValidation = enabled; sParanoidValidation = enabled;
} }
extern "C" void static void
heap_debug_set_memory_reuse(bool enabled) debug_heap_set_memory_reuse(bool enabled)
{ {
sReuseMemory = enabled; sReuseMemory = enabled;
} }
extern "C" void static void
heap_debug_set_debugger_calls(bool enabled) debug_heap_set_debugger_calls(bool enabled)
{ {
sDebuggerCalls = enabled; sDebuggerCalls = enabled;
} }
extern "C" void static void
heap_debug_set_default_alignment(size_t defaultAlignment) debug_heap_set_default_alignment(size_t defaultAlignment)
{ {
sDefaultAlignment = defaultAlignment; sDefaultAlignment = defaultAlignment;
} }
extern "C" void static void
heap_debug_validate_heaps() debug_heap_validate_heaps()
{ {
for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++)
heap_validate_heap(sHeaps[i]); heap_validate_heap(sHeaps[i]);
} }
extern "C" void static void
heap_debug_validate_walls() debug_heap_dump_heaps(bool dumpAreas, bool dumpBins)
{
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)
{ {
for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++)
dump_allocator(sHeaps[i], dumpAreas, dumpBins); dump_allocator(sHeaps[i], dumpAreas, dumpBins);
} }
extern "C" void * static void *
heap_debug_malloc_with_guard_page(size_t size) debug_heap_malloc_with_guard_page(size_t size)
{ {
size_t areaSize = ROUNDUP(size + sizeof(area_allocation_info) + B_PAGE_SIZE, size_t areaSize = ROUNDUP(size + sizeof(area_allocation_info) + B_PAGE_SIZE,
B_PAGE_SIZE); B_PAGE_SIZE);
@@ -1775,8 +1757,8 @@ heap_debug_malloc_with_guard_page(size_t size)
} }
extern "C" status_t static status_t
heap_debug_get_allocation_info(void *address, size_t *size, debug_heap_get_allocation_info(void *address, size_t *size,
thread_id *thread) thread_id *thread)
{ {
for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) { 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 // #pragma mark - Init
extern "C" status_t static status_t
__init_heap(void) debug_heap_init(void)
{ {
// This will locate the heap base at 384 MB and reserve the next 1152 MB // 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 // 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 // #pragma mark - Public API
extern "C" void * static void *
sbrk_hook(long) debug_heap_memalign(size_t alignment, size_t size)
{
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)
{ {
size_t alignedSize = size + sizeof(addr_t) + sizeof(heap_leak_check_info); size_t alignedSize = size + sizeof(addr_t) + sizeof(heap_leak_check_info);
if (alignment != 0 && alignment < B_PAGE_SIZE) if (alignment != 0 && alignment < B_PAGE_SIZE)
@@ -1974,18 +1900,18 @@ memalign(size_t alignment, size_t size)
} }
void * static void *
malloc(size_t size) debug_heap_malloc(size_t size)
{ {
if (sUseGuardPage) 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 static void
free(void *address) debug_heap_free(void *address)
{ {
for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) { for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
heap_allocator *heap = sHeaps[i]; heap_allocator *heap = sHeaps[i];
@@ -2017,11 +1943,11 @@ free(void *address)
} }
void * static void *
realloc(void *address, size_t newSize) debug_heap_realloc(void *address, size_t newSize)
{ {
if (address == NULL) if (address == NULL)
return memalign(sDefaultAlignment, newSize); return debug_heap_memalign(sDefaultAlignment, newSize);
if (newSize == 0) { if (newSize == 0) {
free(address); free(address);
@@ -2079,7 +2005,7 @@ realloc(void *address, size_t newSize)
} }
// have to allocate/copy/free - TODO maybe resize the area instead? // have to allocate/copy/free - TODO maybe resize the area instead?
newAddress = malloc(newSize); newAddress = debug_heap_memalign(sDefaultAlignment, newSize);
if (newAddress == NULL) { if (newAddress == NULL) {
panic("realloc(): failed to allocate new block of %ld" panic("realloc(): failed to allocate new block of %ld"
" bytes\n", newSize); " bytes\n", newSize);
@@ -2100,33 +2026,32 @@ realloc(void *address, size_t newSize)
} }
void * heap_implementation __mallocDebugHeap = {
calloc(size_t numElements, size_t size) debug_heap_init,
{ NULL, // terminate_after
void *address = malloc(numElements * size);
if (address != NULL)
memset(address, 0, numElements * size);
return address; debug_heap_memalign,
} debug_heap_malloc,
debug_heap_free,
debug_heap_realloc,
NULL, // calloc
NULL, // valloc
NULL, // posix_memalign
extern "C" void * debug_heap_start_wall_checking,
valloc(size_t size) debug_heap_stop_wall_checking,
{ debug_heap_set_paranoid_validation,
return memalign(B_PAGE_SIZE, size); 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,
NULL, // set_dump_allocations_on_exit
extern "C" int NULL // set_stack_trace_depth
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;
}
@@ -0,0 +1,283 @@
/*
* Copyright 2015, Michael Lotz <mmlr@mlotz.ch>.
* Distributed under the terms of the MIT License.
*/
#include "malloc_debug_api.h"
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
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;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2015, Michael Lotz <mmlr@mlotz.ch>.
* Distributed under the terms of the MIT License.
*/
#ifndef MALLOC_DEBUG_API_H
#define MALLOC_DEBUG_API_H
#include <OS.h>
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
+5
View File
@@ -205,7 +205,12 @@ __init_env(const struct user_space_program_args *args)
// protect our implementation // protect our implementation
environ = args->env; environ = args->env;
sManagedEnviron = NULL; sManagedEnviron = NULL;
}
void
__init_env_post_heap()
{
atfork(environ_fork_hook); atfork(environ_fork_hook);
} }
+1 -1
View File
@@ -892,8 +892,8 @@ void __ilogb() {}
void __ilogbf() {} void __ilogbf() {}
void __ilogbl() {} void __ilogbl() {}
void __init_env() {} void __init_env() {}
void __init_env_post_heap() {}
void __init_heap() {} void __init_heap() {}
void __init_heap_post_env() {}
void __init_once() {} void __init_once() {}
void __init_pthread() {} void __init_pthread() {}
void __init_pwd_backend() {} void __init_pwd_backend() {}
@@ -726,8 +726,8 @@ void __ilogb() {}
void __ilogbf() {} void __ilogbf() {}
void __ilogbl() {} void __ilogbl() {}
void __init_env() {} void __init_env() {}
void __init_env_post_heap() {}
void __init_heap() {} void __init_heap() {}
void __init_heap_post_env() {}
void __init_once() {} void __init_once() {}
void __init_pthread() {} void __init_pthread() {}
void __init_pwd_backend() {} void __init_pwd_backend() {}