1/* 2 * Copyright 2015, Michael Lotz <mmlr@mlotz.ch>. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "malloc_debug_api.h" 8 9#include <malloc.h> 10#include <string.h> 11 12#include <stdio.h> 13#include <stdlib.h> 14 15 16static heap_implementation* sCurrentHeap = NULL; 17 18 19// #pragma mark - Heap Debug API 20 21 22extern "C" status_t 23heap_debug_start_wall_checking(int msInterval) 24{ 25 if (sCurrentHeap->start_wall_checking != NULL) 26 return sCurrentHeap->start_wall_checking(msInterval); 27 28 return B_NOT_SUPPORTED; 29} 30 31 32extern "C" status_t 33heap_debug_stop_wall_checking() 34{ 35 if (sCurrentHeap->stop_wall_checking != NULL) 36 return sCurrentHeap->stop_wall_checking(); 37 38 return B_NOT_SUPPORTED; 39} 40 41 42extern "C" void 43heap_debug_set_paranoid_validation(bool enabled) 44{ 45 if (sCurrentHeap->set_paranoid_validation != NULL) 46 sCurrentHeap->set_paranoid_validation(enabled); 47} 48 49 50extern "C" void 51heap_debug_set_memory_reuse(bool enabled) 52{ 53 if (sCurrentHeap->set_memory_reuse != NULL) 54 sCurrentHeap->set_memory_reuse(enabled); 55} 56 57 58extern "C" void 59heap_debug_set_debugger_calls(bool enabled) 60{ 61 if (sCurrentHeap->set_debugger_calls != NULL) 62 sCurrentHeap->set_debugger_calls(enabled); 63} 64 65 66extern "C" void 67heap_debug_set_default_alignment(size_t defaultAlignment) 68{ 69 if (sCurrentHeap->set_default_alignment != NULL) 70 sCurrentHeap->set_default_alignment(defaultAlignment); 71} 72 73 74extern "C" void 75heap_debug_validate_heaps() 76{ 77 if (sCurrentHeap->validate_heaps != NULL) 78 sCurrentHeap->validate_heaps(); 79} 80 81 82extern "C" void 83heap_debug_validate_walls() 84{ 85 if (sCurrentHeap->validate_walls != NULL) 86 sCurrentHeap->validate_walls(); 87} 88 89 90extern "C" void 91heap_debug_dump_allocations(bool statsOnly, thread_id thread) 92{ 93 if (sCurrentHeap->dump_allocations != NULL) 94 sCurrentHeap->dump_allocations(statsOnly, thread); 95} 96 97 98extern "C" void 99heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) 100{ 101 if (sCurrentHeap->dump_heaps != NULL) 102 sCurrentHeap->dump_heaps(dumpAreas, dumpBins); 103} 104 105 106extern "C" void * 107heap_debug_malloc_with_guard_page(size_t size) 108{ 109 if (sCurrentHeap->malloc_with_guard_page != NULL) 110 return sCurrentHeap->malloc_with_guard_page(size); 111 112 return NULL; 113} 114 115 116extern "C" status_t 117heap_debug_get_allocation_info(void *address, size_t *size, 118 thread_id *thread) 119{ 120 if (sCurrentHeap->get_allocation_info != NULL) 121 return sCurrentHeap->get_allocation_info(address, size, thread); 122 123 return B_NOT_SUPPORTED; 124} 125 126 127extern "C" status_t 128heap_debug_set_dump_allocations_on_exit(bool enabled) 129{ 130 if (sCurrentHeap->set_dump_allocations_on_exit != NULL) 131 return sCurrentHeap->set_dump_allocations_on_exit(enabled); 132 133 return B_NOT_SUPPORTED; 134} 135 136 137extern "C" status_t 138heap_debug_set_stack_trace_depth(size_t stackTraceDepth) 139{ 140 if (sCurrentHeap->set_stack_trace_depth != NULL) 141 return sCurrentHeap->set_stack_trace_depth(stackTraceDepth); 142 143 return B_NOT_SUPPORTED; 144} 145 146 147// #pragma mark - Init 148 149 150extern "C" status_t 151__init_heap(void) 152{ 153 const char *mode = getenv("MALLOC_DEBUG"); 154 if (mode == NULL || strchr(mode, 'g') == NULL) 155 sCurrentHeap = &__mallocDebugHeap; 156 else 157 sCurrentHeap = &__mallocGuardedHeap; 158 159 status_t result = sCurrentHeap->init(); 160 if (result != B_OK) 161 return result; 162 163 if (mode != NULL) { 164 if (strchr(mode, 'p') != NULL) 165 heap_debug_set_paranoid_validation(true); 166 if (strchr(mode, 'r') != NULL) 167 heap_debug_set_memory_reuse(false); 168 if (strchr(mode, 'e') != NULL) 169 heap_debug_set_dump_allocations_on_exit(true); 170 171 size_t defaultAlignment = 0; 172 const char *argument = strchr(mode, 'a'); 173 if (argument != NULL 174 && sscanf(argument, "a%" B_SCNuSIZE, &defaultAlignment) == 1) { 175 heap_debug_set_default_alignment(defaultAlignment); 176 } 177 178 size_t stackTraceDepth = 0; 179 argument = strchr(mode, 's'); 180 if (argument != NULL 181 && sscanf(argument, "s%" B_SCNuSIZE, &stackTraceDepth) == 1) { 182 heap_debug_set_stack_trace_depth(stackTraceDepth); 183 } 184 185 int wallCheckInterval = 0; 186 argument = strchr(mode, 'w'); 187 if (argument != NULL 188 && sscanf(argument, "w%d", &wallCheckInterval) == 1) { 189 heap_debug_start_wall_checking(wallCheckInterval); 190 } 191 } 192 193 return B_OK; 194} 195 196 197extern "C" void 198__heap_terminate_after() 199{ 200 if (sCurrentHeap->terminate_after != NULL) 201 sCurrentHeap->terminate_after(); 202} 203 204 205extern "C" void 206__heap_before_fork(void) 207{ 208} 209 210 211extern "C" void 212__heap_after_fork_child(void) 213{ 214} 215 216 217extern "C" void 218__heap_after_fork_parent(void) 219{ 220} 221 222 223extern "C" void 224__heap_thread_init(void) 225{ 226} 227 228 229extern "C" void 230__heap_thread_exit(void) 231{ 232} 233 234 235// #pragma mark - Public API 236 237 238extern "C" void* 239memalign(size_t alignment, size_t size) 240{ 241 return sCurrentHeap->memalign(alignment, size); 242} 243 244 245extern "C" void* 246aligned_alloc(size_t alignment, size_t size) 247{ 248 if ((size % alignment) != 0) 249 return NULL; 250 251 return sCurrentHeap->memalign(alignment, size); 252} 253 254 255extern "C" void* 256malloc(size_t size) 257{ 258 return sCurrentHeap->malloc(size); 259} 260 261 262extern "C" void 263free(void* address) 264{ 265 sCurrentHeap->free(address); 266} 267 268 269extern "C" void* 270realloc(void* address, size_t newSize) 271{ 272 return sCurrentHeap->realloc(address, newSize); 273} 274 275 276extern "C" void* 277calloc(size_t numElements, size_t size) 278{ 279 if (sCurrentHeap->calloc != NULL) 280 return sCurrentHeap->calloc(numElements, size); 281 282 void* address = malloc(numElements * size); 283 if (address != NULL) 284 memset(address, 0, numElements * size); 285 286 return address; 287} 288 289 290extern "C" void* 291valloc(size_t size) 292{ 293 if (sCurrentHeap->valloc != NULL) 294 return sCurrentHeap->valloc(size); 295 296 return memalign(B_PAGE_SIZE, size); 297} 298 299 300extern "C" int 301posix_memalign(void **pointer, size_t alignment, size_t size) 302{ 303 if (sCurrentHeap->posix_memalign != NULL) 304 return sCurrentHeap->posix_memalign(pointer, alignment, size); 305 306 if (!is_valid_alignment(alignment)) 307 return EINVAL; 308 309 *pointer = memalign(alignment, size); 310 if (*pointer == NULL) 311 return ENOMEM; 312 313 return 0; 314} 315 316 317extern "C" size_t 318malloc_usable_size(void *ptr) 319{ 320 size_t size; 321 thread_id thread; 322 323 if (ptr == NULL) 324 return 0; 325 326 status_t res = sCurrentHeap->get_allocation_info(ptr, &size, &thread); 327 328 if (res != B_OK) 329 return 0; 330 331 return size; 332} 333