1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <errno.h> 30 #include <inttypes.h> 31 #include <malloc.h> 32 #include <string.h> 33 #include <sys/cdefs.h> 34 #include <sys/param.h> 35 #include <unistd.h> 36 37 #include <vector> 38 39 #include <private/bionic_malloc_dispatch.h> 40 41 #include "backtrace.h" 42 #include "Config.h" 43 #include "DebugData.h" 44 #include "debug_disable.h" 45 #include "debug_log.h" 46 #include "malloc_debug.h" 47 48 // ------------------------------------------------------------------------ 49 // Global Data 50 // ------------------------------------------------------------------------ 51 DebugData* g_debug; 52 53 int* g_malloc_zygote_child; 54 55 const MallocDispatch* g_dispatch; 56 // ------------------------------------------------------------------------ 57 58 // ------------------------------------------------------------------------ 59 // Use C style prototypes for all exported functions. This makes it easy 60 // to do dlsym lookups during libc initialization when malloc debug 61 // is enabled. 62 // ------------------------------------------------------------------------ 63 __BEGIN_DECLS 64 65 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child, 66 const char* options); 67 void debug_finalize(); 68 void debug_get_malloc_leak_info( 69 uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, 70 size_t* backtrace_size); 71 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count); 72 void debug_free_malloc_leak_info(uint8_t* info); 73 size_t debug_malloc_usable_size(void* pointer); 74 void* debug_malloc(size_t size); 75 void debug_free(void* pointer); 76 void* debug_memalign(size_t alignment, size_t bytes); 77 void* debug_realloc(void* pointer, size_t bytes); 78 void* debug_calloc(size_t nmemb, size_t bytes); 79 struct mallinfo debug_mallinfo(); 80 int debug_mallopt(int param, int value); 81 int debug_posix_memalign(void** memptr, size_t alignment, size_t size); 82 int debug_iterate(uintptr_t base, size_t size, 83 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg); 84 void debug_malloc_disable(); 85 void debug_malloc_enable(); 86 87 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) 88 void* debug_pvalloc(size_t bytes); 89 void* debug_valloc(size_t size); 90 #endif 91 92 __END_DECLS 93 // ------------------------------------------------------------------------ 94 95 static void InitAtfork() { 96 static pthread_once_t atfork_init = PTHREAD_ONCE_INIT; 97 pthread_once(&atfork_init, [](){ 98 pthread_atfork( 99 [](){ 100 if (g_debug != nullptr) { 101 g_debug->PrepareFork(); 102 } 103 }, 104 [](){ 105 if (g_debug != nullptr) { 106 g_debug->PostForkParent(); 107 } 108 }, 109 [](){ 110 if (g_debug != nullptr) { 111 g_debug->PostForkChild(); 112 } 113 } 114 ); 115 }); 116 } 117 118 static void LogTagError(const Header* header, const void* pointer, const char* name) { 119 error_log(LOG_DIVIDER); 120 if (header->tag == DEBUG_FREE_TAG) { 121 error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name); 122 if (g_debug->config().options & FREE_TRACK) { 123 g_debug->free_track->LogBacktrace(header); 124 } 125 } else { 126 error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name); 127 } 128 error_log("Backtrace at time of failure:"); 129 std::vector<uintptr_t> frames(64); 130 size_t frame_num = backtrace_get(frames.data(), frames.size()); 131 frames.resize(frame_num); 132 backtrace_log(frames.data(), frames.size()); 133 error_log(LOG_DIVIDER); 134 } 135 136 static void* InitHeader(Header* header, void* orig_pointer, size_t size) { 137 header->tag = DEBUG_TAG; 138 header->orig_pointer = orig_pointer; 139 header->size = size; 140 if (*g_malloc_zygote_child) { 141 header->set_zygote(); 142 } 143 header->usable_size = g_dispatch->malloc_usable_size(orig_pointer); 144 if (header->usable_size == 0) { 145 g_dispatch->free(orig_pointer); 146 return nullptr; 147 } 148 header->usable_size -= g_debug->pointer_offset() + 149 reinterpret_cast<uintptr_t>(header) - reinterpret_cast<uintptr_t>(orig_pointer); 150 151 if (g_debug->config().options & FRONT_GUARD) { 152 uint8_t* guard = g_debug->GetFrontGuard(header); 153 memset(guard, g_debug->config().front_guard_value, g_debug->config().front_guard_bytes); 154 } 155 156 if (g_debug->config().options & REAR_GUARD) { 157 uint8_t* guard = g_debug->GetRearGuard(header); 158 memset(guard, g_debug->config().rear_guard_value, g_debug->config().rear_guard_bytes); 159 // If the rear guard is enabled, set the usable size to the exact size 160 // of the allocation. 161 header->usable_size = header->real_size(); 162 } 163 164 bool backtrace_found = false; 165 if (g_debug->config().options & BACKTRACE) { 166 BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header); 167 if (g_debug->backtrace->enabled()) { 168 back_header->num_frames = backtrace_get( 169 &back_header->frames[0], g_debug->config().backtrace_frames); 170 backtrace_found = back_header->num_frames > 0; 171 } else { 172 back_header->num_frames = 0; 173 } 174 } 175 176 if (g_debug->config().options & TRACK_ALLOCS) { 177 g_debug->track->Add(header, backtrace_found); 178 } 179 180 return g_debug->GetPointer(header); 181 } 182 183 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child, 184 const char* options) { 185 if (malloc_zygote_child == nullptr || options == nullptr) { 186 return false; 187 } 188 189 InitAtfork(); 190 191 g_malloc_zygote_child = malloc_zygote_child; 192 193 g_dispatch = malloc_dispatch; 194 195 if (!DebugDisableInitialize()) { 196 return false; 197 } 198 199 DebugData* debug = new DebugData(); 200 if (!debug->Initialize(options)) { 201 delete debug; 202 DebugDisableFinalize(); 203 return false; 204 } 205 g_debug = debug; 206 207 // Always enable the backtrace code since we will use it in a number 208 // of different error cases. 209 backtrace_startup(); 210 211 return true; 212 } 213 214 void debug_finalize() { 215 if (g_debug == nullptr) { 216 return; 217 } 218 219 if (g_debug->config().options & FREE_TRACK) { 220 g_debug->free_track->VerifyAll(); 221 } 222 223 if (g_debug->config().options & LEAK_TRACK) { 224 g_debug->track->DisplayLeaks(); 225 } 226 227 DebugDisableSet(true); 228 229 backtrace_shutdown(); 230 231 delete g_debug; 232 g_debug = nullptr; 233 234 DebugDisableFinalize(); 235 } 236 237 void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, 238 size_t* info_size, size_t* total_memory, size_t* backtrace_size) { 239 ScopedDisableDebugCalls disable; 240 241 // Verify the arguments. 242 if (info == nullptr || overall_size == nullptr || info_size == NULL || 243 total_memory == nullptr || backtrace_size == nullptr) { 244 error_log("get_malloc_leak_info: At least one invalid parameter."); 245 return; 246 } 247 248 *info = nullptr; 249 *overall_size = 0; 250 *info_size = 0; 251 *total_memory = 0; 252 *backtrace_size = 0; 253 254 if (!(g_debug->config().options & BACKTRACE)) { 255 error_log("get_malloc_leak_info: Allocations not being tracked, to enable " 256 "set the option 'backtrace'."); 257 return; 258 } 259 260 g_debug->track->GetInfo(info, overall_size, info_size, total_memory, backtrace_size); 261 } 262 263 void debug_free_malloc_leak_info(uint8_t* info) { 264 g_dispatch->free(info); 265 } 266 267 static size_t internal_malloc_usable_size(void* pointer) { 268 if (g_debug->need_header()) { 269 Header* header = g_debug->GetHeader(pointer); 270 if (header->tag != DEBUG_TAG) { 271 LogTagError(header, pointer, "malloc_usable_size"); 272 return 0; 273 } 274 275 return header->usable_size; 276 } else { 277 return g_dispatch->malloc_usable_size(pointer); 278 } 279 } 280 281 size_t debug_malloc_usable_size(void* pointer) { 282 if (DebugCallsDisabled() || pointer == nullptr) { 283 return g_dispatch->malloc_usable_size(pointer); 284 } 285 ScopedDisableDebugCalls disable; 286 287 return internal_malloc_usable_size(pointer); 288 } 289 290 static void *internal_malloc(size_t size) { 291 if (size == 0) { 292 size = 1; 293 } 294 295 size_t real_size = size + g_debug->extra_bytes(); 296 if (real_size < size) { 297 // Overflow. 298 errno = ENOMEM; 299 return nullptr; 300 } 301 302 void* pointer; 303 if (g_debug->need_header()) { 304 if (size > Header::max_size()) { 305 errno = ENOMEM; 306 return nullptr; 307 } 308 309 Header* header = reinterpret_cast<Header*>( 310 g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size)); 311 if (header == nullptr) { 312 return nullptr; 313 } 314 pointer = InitHeader(header, header, size); 315 } else { 316 pointer = g_dispatch->malloc(real_size); 317 } 318 319 if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) { 320 size_t bytes = internal_malloc_usable_size(pointer); 321 size_t fill_bytes = g_debug->config().fill_on_alloc_bytes; 322 bytes = (bytes < fill_bytes) ? bytes : fill_bytes; 323 memset(pointer, g_debug->config().fill_alloc_value, bytes); 324 } 325 return pointer; 326 } 327 328 void* debug_malloc(size_t size) { 329 if (DebugCallsDisabled()) { 330 return g_dispatch->malloc(size); 331 } 332 ScopedDisableDebugCalls disable; 333 334 void* pointer = internal_malloc(size); 335 336 if (g_debug->config().options & RECORD_ALLOCS) { 337 g_debug->record->AddEntry(new MallocEntry(pointer, size)); 338 } 339 340 return pointer; 341 } 342 343 static void internal_free(void* pointer) { 344 void* free_pointer = pointer; 345 size_t bytes; 346 Header* header; 347 if (g_debug->need_header()) { 348 header = g_debug->GetHeader(pointer); 349 if (header->tag != DEBUG_TAG) { 350 LogTagError(header, pointer, "free"); 351 return; 352 } 353 free_pointer = header->orig_pointer; 354 355 if (g_debug->config().options & FRONT_GUARD) { 356 if (!g_debug->front_guard->Valid(header)) { 357 g_debug->front_guard->LogFailure(header); 358 } 359 } 360 if (g_debug->config().options & REAR_GUARD) { 361 if (!g_debug->rear_guard->Valid(header)) { 362 g_debug->rear_guard->LogFailure(header); 363 } 364 } 365 366 if (g_debug->config().options & TRACK_ALLOCS) { 367 bool backtrace_found = false; 368 if (g_debug->config().options & BACKTRACE) { 369 BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header); 370 backtrace_found = back_header->num_frames > 0; 371 } 372 g_debug->track->Remove(header, backtrace_found); 373 } 374 header->tag = DEBUG_FREE_TAG; 375 376 bytes = header->usable_size; 377 } else { 378 bytes = g_dispatch->malloc_usable_size(pointer); 379 } 380 381 if (g_debug->config().options & FILL_ON_FREE) { 382 size_t fill_bytes = g_debug->config().fill_on_free_bytes; 383 bytes = (bytes < fill_bytes) ? bytes : fill_bytes; 384 memset(pointer, g_debug->config().fill_free_value, bytes); 385 } 386 387 if (g_debug->config().options & FREE_TRACK) { 388 // Do not add the allocation until we are done modifying the pointer 389 // itself. This avoids a race if a lot of threads are all doing 390 // frees at the same time and we wind up trying to really free this 391 // pointer from another thread, while still trying to free it in 392 // this function. 393 g_debug->free_track->Add(header); 394 } else { 395 g_dispatch->free(free_pointer); 396 } 397 } 398 399 void debug_free(void* pointer) { 400 if (DebugCallsDisabled() || pointer == nullptr) { 401 return g_dispatch->free(pointer); 402 } 403 ScopedDisableDebugCalls disable; 404 405 if (g_debug->config().options & RECORD_ALLOCS) { 406 g_debug->record->AddEntry(new FreeEntry(pointer)); 407 } 408 409 internal_free(pointer); 410 } 411 412 void* debug_memalign(size_t alignment, size_t bytes) { 413 if (DebugCallsDisabled()) { 414 return g_dispatch->memalign(alignment, bytes); 415 } 416 ScopedDisableDebugCalls disable; 417 418 if (bytes == 0) { 419 bytes = 1; 420 } 421 422 void* pointer; 423 if (g_debug->need_header()) { 424 if (bytes > Header::max_size()) { 425 errno = ENOMEM; 426 return nullptr; 427 } 428 429 // Make the alignment a power of two. 430 if (!powerof2(alignment)) { 431 alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment); 432 } 433 // Force the alignment to at least MINIMUM_ALIGNMENT_BYTES to guarantee 434 // that the header is aligned properly. 435 if (alignment < MINIMUM_ALIGNMENT_BYTES) { 436 alignment = MINIMUM_ALIGNMENT_BYTES; 437 } 438 439 // We don't have any idea what the natural alignment of 440 // the underlying native allocator is, so we always need to 441 // over allocate. 442 size_t real_size = alignment + bytes + g_debug->extra_bytes(); 443 if (real_size < bytes) { 444 // Overflow. 445 errno = ENOMEM; 446 return nullptr; 447 } 448 449 pointer = g_dispatch->malloc(real_size); 450 if (pointer == nullptr) { 451 return nullptr; 452 } 453 454 uintptr_t value = reinterpret_cast<uintptr_t>(pointer) + g_debug->pointer_offset(); 455 // Now align the pointer. 456 value += (-value % alignment); 457 458 Header* header = g_debug->GetHeader(reinterpret_cast<void*>(value)); 459 pointer = InitHeader(header, pointer, bytes); 460 } else { 461 size_t real_size = bytes + g_debug->extra_bytes(); 462 if (real_size < bytes) { 463 // Overflow. 464 errno = ENOMEM; 465 return nullptr; 466 } 467 pointer = g_dispatch->memalign(alignment, real_size); 468 } 469 470 if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) { 471 size_t bytes = internal_malloc_usable_size(pointer); 472 size_t fill_bytes = g_debug->config().fill_on_alloc_bytes; 473 bytes = (bytes < fill_bytes) ? bytes : fill_bytes; 474 memset(pointer, g_debug->config().fill_alloc_value, bytes); 475 } 476 477 if (g_debug->config().options & RECORD_ALLOCS) { 478 g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment)); 479 } 480 481 return pointer; 482 } 483 484 void* debug_realloc(void* pointer, size_t bytes) { 485 if (DebugCallsDisabled()) { 486 return g_dispatch->realloc(pointer, bytes); 487 } 488 ScopedDisableDebugCalls disable; 489 490 if (pointer == nullptr) { 491 pointer = internal_malloc(bytes); 492 if (g_debug->config().options & RECORD_ALLOCS) { 493 g_debug->record->AddEntry(new ReallocEntry(pointer, bytes, nullptr)); 494 } 495 return pointer; 496 } 497 498 if (bytes == 0) { 499 if (g_debug->config().options & RECORD_ALLOCS) { 500 g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer)); 501 } 502 503 internal_free(pointer); 504 return nullptr; 505 } 506 507 size_t real_size = bytes; 508 if (g_debug->config().options & EXPAND_ALLOC) { 509 real_size += g_debug->config().expand_alloc_bytes; 510 if (real_size < bytes) { 511 // Overflow. 512 errno = ENOMEM; 513 return nullptr; 514 } 515 } 516 517 void* new_pointer; 518 size_t prev_size; 519 if (g_debug->need_header()) { 520 if (bytes > Header::max_size()) { 521 errno = ENOMEM; 522 return nullptr; 523 } 524 525 Header* header = g_debug->GetHeader(pointer); 526 if (header->tag != DEBUG_TAG) { 527 LogTagError(header, pointer, "realloc"); 528 return nullptr; 529 } 530 531 // Same size, do nothing. 532 if (real_size == header->real_size()) { 533 // Do not bother recording, this is essentially a nop. 534 return pointer; 535 } 536 537 // Allocation is shrinking. 538 if (real_size < header->usable_size) { 539 header->size = real_size; 540 if (*g_malloc_zygote_child) { 541 header->set_zygote(); 542 } 543 if (g_debug->config().options & REAR_GUARD) { 544 // Don't bother allocating a smaller pointer in this case, simply 545 // change the header usable_size and reset the rear guard. 546 header->usable_size = header->real_size(); 547 memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value, 548 g_debug->config().rear_guard_bytes); 549 } 550 // Do not bother recording, this is essentially a nop. 551 return pointer; 552 } 553 554 // Allocate the new size. 555 new_pointer = internal_malloc(bytes); 556 if (new_pointer == nullptr) { 557 errno = ENOMEM; 558 return nullptr; 559 } 560 561 prev_size = header->usable_size; 562 memcpy(new_pointer, pointer, prev_size); 563 internal_free(pointer); 564 } else { 565 prev_size = g_dispatch->malloc_usable_size(pointer); 566 new_pointer = g_dispatch->realloc(pointer, real_size); 567 if (new_pointer == nullptr) { 568 return nullptr; 569 } 570 } 571 572 if (g_debug->config().options & FILL_ON_ALLOC) { 573 size_t bytes = internal_malloc_usable_size(new_pointer); 574 if (bytes > g_debug->config().fill_on_alloc_bytes) { 575 bytes = g_debug->config().fill_on_alloc_bytes; 576 } 577 if (bytes > prev_size) { 578 memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_pointer) + prev_size), 579 g_debug->config().fill_alloc_value, bytes - prev_size); 580 } 581 } 582 583 if (g_debug->config().options & RECORD_ALLOCS) { 584 g_debug->record->AddEntry(new ReallocEntry(new_pointer, bytes, pointer)); 585 } 586 587 return new_pointer; 588 } 589 590 void* debug_calloc(size_t nmemb, size_t bytes) { 591 if (DebugCallsDisabled()) { 592 return g_dispatch->calloc(nmemb, bytes); 593 } 594 ScopedDisableDebugCalls disable; 595 596 size_t size; 597 if (__builtin_mul_overflow(nmemb, bytes, &size)) { 598 // Overflow 599 errno = ENOMEM; 600 return nullptr; 601 } 602 603 if (size == 0) { 604 size = 1; 605 } 606 607 size_t real_size; 608 if (__builtin_add_overflow(size, g_debug->extra_bytes(), &real_size)) { 609 // Overflow. 610 errno = ENOMEM; 611 return nullptr; 612 } 613 614 void* pointer; 615 if (g_debug->need_header()) { 616 // The above check will guarantee the multiply will not overflow. 617 if (size > Header::max_size()) { 618 errno = ENOMEM; 619 return nullptr; 620 } 621 622 // Need to guarantee the alignment of the header. 623 Header* header = reinterpret_cast<Header*>( 624 g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size)); 625 if (header == nullptr) { 626 return nullptr; 627 } 628 memset(header, 0, g_dispatch->malloc_usable_size(header)); 629 pointer = InitHeader(header, header, size); 630 } else { 631 pointer = g_dispatch->calloc(1, real_size); 632 } 633 if (g_debug->config().options & RECORD_ALLOCS) { 634 g_debug->record->AddEntry(new CallocEntry(pointer, bytes, nmemb)); 635 } 636 return pointer; 637 } 638 639 struct mallinfo debug_mallinfo() { 640 return g_dispatch->mallinfo(); 641 } 642 643 int debug_mallopt(int param, int value) { 644 return g_dispatch->mallopt(param, value); 645 } 646 647 int debug_posix_memalign(void** memptr, size_t alignment, size_t size) { 648 if (DebugCallsDisabled()) { 649 return g_dispatch->posix_memalign(memptr, alignment, size); 650 } 651 652 if (!powerof2(alignment)) { 653 return EINVAL; 654 } 655 int saved_errno = errno; 656 *memptr = debug_memalign(alignment, size); 657 errno = saved_errno; 658 return (*memptr != nullptr) ? 0 : ENOMEM; 659 } 660 661 int debug_iterate(uintptr_t base, size_t size, 662 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) { 663 // Can't allocate, malloc is disabled 664 // Manual capture of the arguments to pass to the lambda below as void* arg 665 struct iterate_ctx { 666 decltype(callback) callback; 667 decltype(arg) arg; 668 } ctx = { callback, arg }; 669 670 return g_dispatch->iterate(base, size, 671 [](uintptr_t base, size_t size, void* arg) { 672 const iterate_ctx* ctx = reinterpret_cast<iterate_ctx*>(arg); 673 const void* pointer = reinterpret_cast<void*>(base); 674 if (g_debug->need_header()) { 675 const Header* header = reinterpret_cast<const Header*>(pointer); 676 if (g_debug->config().options & TRACK_ALLOCS) { 677 if (g_debug->track->Contains(header)) { 678 // Return just the body of the allocation if we're sure the header exists 679 ctx->callback(reinterpret_cast<uintptr_t>(g_debug->GetPointer(header)), 680 header->usable_size, ctx->arg); 681 return; 682 } 683 } 684 } 685 // Fall back to returning the whole allocation 686 ctx->callback(base, size, ctx->arg); 687 }, &ctx); 688 } 689 690 void debug_malloc_disable() { 691 g_dispatch->malloc_disable(); 692 if (g_debug->track) { 693 g_debug->track->PrepareFork(); 694 } 695 } 696 697 void debug_malloc_enable() { 698 if (g_debug->track) { 699 g_debug->track->PostForkParent(); 700 } 701 g_dispatch->malloc_enable(); 702 } 703 704 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) { 705 if (DebugCallsDisabled() || pointer == nullptr) { 706 return 0; 707 } 708 ScopedDisableDebugCalls disable; 709 710 if (g_debug->need_header()) { 711 Header* header; 712 if (g_debug->config().options & TRACK_ALLOCS) { 713 header = g_debug->GetHeader(pointer); 714 if (!g_debug->track->Contains(header)) { 715 return 0; 716 } 717 } else { 718 header = reinterpret_cast<Header*>(pointer); 719 } 720 if (header->tag != DEBUG_TAG) { 721 return 0; 722 } 723 if (g_debug->config().options & BACKTRACE) { 724 BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header); 725 if (back_header->num_frames > 0) { 726 if (frame_count > back_header->num_frames) { 727 frame_count = back_header->num_frames; 728 } 729 memcpy(frames, &back_header->frames[0], frame_count * sizeof(uintptr_t)); 730 return frame_count; 731 } 732 } 733 } 734 735 return 0; 736 } 737 738 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) 739 void* debug_pvalloc(size_t bytes) { 740 if (DebugCallsDisabled()) { 741 return g_dispatch->pvalloc(bytes); 742 } 743 744 size_t pagesize = getpagesize(); 745 size_t size = BIONIC_ALIGN(bytes, pagesize); 746 if (size < bytes) { 747 // Overflow 748 errno = ENOMEM; 749 return nullptr; 750 } 751 return debug_memalign(pagesize, size); 752 } 753 754 void* debug_valloc(size_t size) { 755 if (DebugCallsDisabled()) { 756 return g_dispatch->valloc(size); 757 } 758 return debug_memalign(getpagesize(), size); 759 } 760 #endif 761