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 16 static heap_implementation* sCurrentHeap = NULL; 17 18 19 // #pragma mark - Heap Debug API 20 21 22 extern "C" status_t 23 heap_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 32 extern "C" status_t 33 heap_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 42 extern "C" void 43 heap_debug_set_paranoid_validation(bool enabled) 44 { 45 if (sCurrentHeap->set_paranoid_validation != NULL) 46 sCurrentHeap->set_paranoid_validation(enabled); 47 } 48 49 50 extern "C" void 51 heap_debug_set_memory_reuse(bool enabled) 52 { 53 if (sCurrentHeap->set_memory_reuse != NULL) 54 sCurrentHeap->set_memory_reuse(enabled); 55 } 56 57 58 extern "C" void 59 heap_debug_set_debugger_calls(bool enabled) 60 { 61 if (sCurrentHeap->set_debugger_calls != NULL) 62 sCurrentHeap->set_debugger_calls(enabled); 63 } 64 65 66 extern "C" void 67 heap_debug_set_default_alignment(size_t defaultAlignment) 68 { 69 if (sCurrentHeap->set_default_alignment != NULL) 70 sCurrentHeap->set_default_alignment(defaultAlignment); 71 } 72 73 74 extern "C" void 75 heap_debug_validate_heaps() 76 { 77 if (sCurrentHeap->validate_heaps != NULL) 78 sCurrentHeap->validate_heaps(); 79 } 80 81 82 extern "C" void 83 heap_debug_validate_walls() 84 { 85 if (sCurrentHeap->validate_walls != NULL) 86 sCurrentHeap->validate_walls(); 87 } 88 89 90 extern "C" void 91 heap_debug_dump_allocations(bool statsOnly, thread_id thread) 92 { 93 if (sCurrentHeap->dump_allocations != NULL) 94 sCurrentHeap->dump_allocations(statsOnly, thread); 95 } 96 97 98 extern "C" void 99 heap_debug_dump_heaps(bool dumpAreas, bool dumpBins) 100 { 101 if (sCurrentHeap->dump_heaps != NULL) 102 sCurrentHeap->dump_heaps(dumpAreas, dumpBins); 103 } 104 105 106 extern "C" void * 107 heap_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 116 extern "C" status_t 117 heap_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 127 extern "C" status_t 128 heap_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 137 extern "C" status_t 138 heap_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 150 extern "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 197 extern "C" void 198 __heap_terminate_after() 199 { 200 if (sCurrentHeap->terminate_after != NULL) 201 sCurrentHeap->terminate_after(); 202 } 203 204 205 extern "C" void 206 __heap_before_fork(void) 207 { 208 } 209 210 211 extern "C" void 212 __heap_after_fork_child(void) 213 { 214 } 215 216 217 extern "C" void 218 __heap_after_fork_parent(void) 219 { 220 } 221 222 223 extern "C" void 224 __heap_thread_init(void) 225 { 226 } 227 228 229 extern "C" void 230 __heap_thread_exit(void) 231 { 232 } 233 234 235 // #pragma mark - Public API 236 237 238 extern "C" void* 239 memalign(size_t alignment, size_t size) 240 { 241 return sCurrentHeap->memalign(alignment, size); 242 } 243 244 245 extern "C" void* 246 aligned_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 255 extern "C" void* 256 malloc(size_t size) 257 { 258 return sCurrentHeap->malloc(size); 259 } 260 261 262 extern "C" void 263 free(void* address) 264 { 265 sCurrentHeap->free(address); 266 } 267 268 269 extern "C" void* 270 realloc(void* address, size_t newSize) 271 { 272 return sCurrentHeap->realloc(address, newSize); 273 } 274 275 276 extern "C" void* 277 calloc(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 290 extern "C" void* 291 valloc(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 300 extern "C" int 301 posix_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 317 extern "C" size_t 318 malloc_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