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:
@@ -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) ;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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) ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user