Home | History | Annotate | Download | only in malloc_debug
      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 void debug_finalize();
     67 void debug_get_malloc_leak_info(
     68     uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
     69     size_t* backtrace_size);
     70 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
     71 void debug_free_malloc_leak_info(uint8_t* info);
     72 size_t debug_malloc_usable_size(void* pointer);
     73 void* debug_malloc(size_t size);
     74 void debug_free(void* pointer);
     75 void* debug_memalign(size_t alignment, size_t bytes);
     76 void* debug_realloc(void* pointer, size_t bytes);
     77 void* debug_calloc(size_t nmemb, size_t bytes);
     78 struct mallinfo debug_mallinfo();
     79 int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
     80 int debug_iterate(uintptr_t base, size_t size,
     81     void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
     82 void debug_malloc_disable();
     83 void debug_malloc_enable();
     84 
     85 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
     86 void* debug_pvalloc(size_t bytes);
     87 void* debug_valloc(size_t size);
     88 #endif
     89 
     90 __END_DECLS
     91 // ------------------------------------------------------------------------
     92 
     93 static void InitAtfork() {
     94   static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
     95   pthread_once(&atfork_init, [](){
     96     pthread_atfork(
     97         [](){
     98           if (g_debug != nullptr) {
     99             g_debug->PrepareFork();
    100           }
    101         },
    102         [](){
    103           if (g_debug != nullptr) {
    104             g_debug->PostForkParent();
    105           }
    106         },
    107         [](){
    108           if (g_debug != nullptr) {
    109             g_debug->PostForkChild();
    110           }
    111         }
    112     );
    113   });
    114 }
    115 
    116 static void LogTagError(const Header* header, const void* pointer, const char* name) {
    117   ScopedDisableDebugCalls disable;
    118 
    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       ScopedDisableDebugCalls disable;
    169       back_header->num_frames = backtrace_get(
    170           &back_header->frames[0], g_debug->config().backtrace_frames);
    171       backtrace_found = back_header->num_frames > 0;
    172     } else {
    173       back_header->num_frames = 0;
    174     }
    175   }
    176 
    177   if (g_debug->config().options & TRACK_ALLOCS) {
    178     g_debug->track->Add(header, backtrace_found);
    179   }
    180 
    181   return g_debug->GetPointer(header);
    182 }
    183 
    184 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child) {
    185   if (malloc_zygote_child == 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()) {
    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(*g_debug);
    221   }
    222 
    223   if (g_debug->config().options & LEAK_TRACK) {
    224     g_debug->track->DisplayLeaks(*g_debug);
    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(*g_debug, 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 size_t debug_malloc_usable_size(void* pointer) {
    268   if (DebugCallsDisabled() || !g_debug->need_header() || pointer == nullptr) {
    269     return g_dispatch->malloc_usable_size(pointer);
    270   }
    271 
    272   Header* header = g_debug->GetHeader(pointer);
    273   if (header->tag != DEBUG_TAG) {
    274     LogTagError(header, pointer, "malloc_usable_size");
    275     return 0;
    276   }
    277 
    278   return header->usable_size;
    279 }
    280 
    281 void* debug_malloc(size_t size) {
    282   if (DebugCallsDisabled()) {
    283     return g_dispatch->malloc(size);
    284   }
    285 
    286   if (size == 0) {
    287     size = 1;
    288   }
    289 
    290   size_t real_size = size + g_debug->extra_bytes();
    291   if (real_size < size) {
    292     // Overflow.
    293     errno = ENOMEM;
    294     return nullptr;
    295   }
    296 
    297   void* pointer;
    298   if (g_debug->need_header()) {
    299     if (size > Header::max_size()) {
    300       errno = ENOMEM;
    301       return nullptr;
    302     }
    303 
    304     Header* header = reinterpret_cast<Header*>(
    305         g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
    306     if (header == nullptr) {
    307       return nullptr;
    308     }
    309     pointer = InitHeader(header, header, size);
    310   } else {
    311     pointer = g_dispatch->malloc(real_size);
    312   }
    313 
    314   if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
    315     size_t bytes = debug_malloc_usable_size(pointer);
    316     size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
    317     bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
    318     memset(pointer, g_debug->config().fill_alloc_value, bytes);
    319   }
    320   return pointer;
    321 }
    322 
    323 void debug_free(void* pointer) {
    324   if (DebugCallsDisabled() || pointer == nullptr) {
    325     return g_dispatch->free(pointer);
    326   }
    327 
    328   void* free_pointer = pointer;
    329   size_t bytes;
    330   Header* header;
    331   if (g_debug->need_header()) {
    332     header = g_debug->GetHeader(pointer);
    333     if (header->tag != DEBUG_TAG) {
    334       LogTagError(header, pointer, "free");
    335       return;
    336     }
    337     free_pointer = header->orig_pointer;
    338 
    339     if (g_debug->config().options & FRONT_GUARD) {
    340       if (!g_debug->front_guard->Valid(*g_debug, header)) {
    341         g_debug->front_guard->LogFailure(*g_debug, header);
    342       }
    343     }
    344     if (g_debug->config().options & REAR_GUARD) {
    345       if (!g_debug->rear_guard->Valid(*g_debug, header)) {
    346         g_debug->rear_guard->LogFailure(*g_debug, header);
    347       }
    348     }
    349 
    350     if (g_debug->config().options & TRACK_ALLOCS) {
    351       bool backtrace_found = false;
    352       if (g_debug->config().options & BACKTRACE) {
    353         BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
    354         backtrace_found = back_header->num_frames > 0;
    355       }
    356       g_debug->track->Remove(header, backtrace_found);
    357     }
    358     header->tag = DEBUG_FREE_TAG;
    359 
    360     bytes = header->usable_size;
    361   } else {
    362     bytes = g_dispatch->malloc_usable_size(pointer);
    363   }
    364 
    365   if (g_debug->config().options & FILL_ON_FREE) {
    366     size_t fill_bytes = g_debug->config().fill_on_free_bytes;
    367     bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
    368     memset(pointer, g_debug->config().fill_free_value, bytes);
    369   }
    370 
    371   if (g_debug->config().options & FREE_TRACK) {
    372     // Do not add the allocation until we are done modifying the pointer
    373     // itself. This avoids a race if a lot of threads are all doing
    374     // frees at the same time and we wind up trying to really free this
    375     // pointer from another thread, while still trying to free it in
    376     // this function.
    377     g_debug->free_track->Add(*g_debug, header);
    378   } else {
    379     g_dispatch->free(free_pointer);
    380   }
    381 }
    382 
    383 void* debug_memalign(size_t alignment, size_t bytes) {
    384   if (DebugCallsDisabled()) {
    385     return g_dispatch->memalign(alignment, bytes);
    386   }
    387 
    388   if (bytes == 0) {
    389     bytes = 1;
    390   }
    391 
    392   void* pointer;
    393   if (g_debug->need_header()) {
    394     if (bytes > Header::max_size()) {
    395       errno = ENOMEM;
    396       return nullptr;
    397     }
    398 
    399     // Make the alignment a power of two.
    400     if (!powerof2(alignment)) {
    401       alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
    402     }
    403     // Force the alignment to at least MINIMUM_ALIGNMENT_BYTES to guarantee
    404     // that the header is aligned properly.
    405     if (alignment < MINIMUM_ALIGNMENT_BYTES) {
    406       alignment = MINIMUM_ALIGNMENT_BYTES;
    407     }
    408 
    409     // We don't have any idea what the natural alignment of
    410     // the underlying native allocator is, so we always need to
    411     // over allocate.
    412     size_t real_size = alignment + bytes + g_debug->extra_bytes();
    413     if (real_size < bytes) {
    414       // Overflow.
    415       errno = ENOMEM;
    416       return nullptr;
    417     }
    418 
    419     pointer = g_dispatch->malloc(real_size);
    420     if (pointer == nullptr) {
    421       return nullptr;
    422     }
    423 
    424     uintptr_t value = reinterpret_cast<uintptr_t>(pointer) + g_debug->pointer_offset();
    425     // Now align the pointer.
    426     value += (-value % alignment);
    427 
    428     Header* header = g_debug->GetHeader(reinterpret_cast<void*>(value));
    429     pointer = InitHeader(header, pointer, bytes);
    430   } else {
    431     size_t real_size = bytes + g_debug->extra_bytes();
    432     if (real_size < bytes) {
    433       // Overflow.
    434       errno = ENOMEM;
    435       return nullptr;
    436     }
    437     pointer = g_dispatch->memalign(alignment, real_size);
    438   }
    439 
    440   if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
    441     size_t bytes = debug_malloc_usable_size(pointer);
    442     size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
    443     bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
    444     memset(pointer, g_debug->config().fill_alloc_value, bytes);
    445   }
    446   return pointer;
    447 }
    448 
    449 void* debug_realloc(void* pointer, size_t bytes) {
    450   if (DebugCallsDisabled()) {
    451     return g_dispatch->realloc(pointer, bytes);
    452   }
    453 
    454   if (pointer == nullptr) {
    455     return debug_malloc(bytes);
    456   }
    457 
    458   if (bytes == 0) {
    459     debug_free(pointer);
    460     return nullptr;
    461   }
    462 
    463   size_t real_size = bytes;
    464   if (g_debug->config().options & EXPAND_ALLOC) {
    465     real_size += g_debug->config().expand_alloc_bytes;
    466     if (real_size < bytes) {
    467       // Overflow.
    468       errno = ENOMEM;
    469       return nullptr;
    470     }
    471   }
    472 
    473   void* new_pointer;
    474   size_t prev_size;
    475   if (g_debug->need_header()) {
    476     if (bytes > Header::max_size()) {
    477       errno = ENOMEM;
    478       return nullptr;
    479     }
    480 
    481     Header* header = g_debug->GetHeader(pointer);
    482     if (header->tag != DEBUG_TAG) {
    483       LogTagError(header, pointer, "realloc");
    484       return nullptr;
    485     }
    486 
    487     // Same size, do nothing.
    488     if (real_size == header->real_size()) {
    489       return pointer;
    490     }
    491 
    492     // Allocation is shrinking.
    493     if (real_size < header->usable_size) {
    494       header->size = real_size;
    495       if (*g_malloc_zygote_child) {
    496         header->set_zygote();
    497       }
    498       if (g_debug->config().options & REAR_GUARD) {
    499         // Don't bother allocating a smaller pointer in this case, simply
    500         // change the header usable_size and reset the rear guard.
    501         header->usable_size = header->real_size();
    502         memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value,
    503                g_debug->config().rear_guard_bytes);
    504       }
    505       return pointer;
    506     }
    507 
    508     // Allocate the new size.
    509     new_pointer = debug_malloc(bytes);
    510     if (new_pointer == nullptr) {
    511       errno = ENOMEM;
    512       return nullptr;
    513     }
    514 
    515     prev_size = header->usable_size;
    516     memcpy(new_pointer, pointer, prev_size);
    517     debug_free(pointer);
    518   } else {
    519     prev_size = g_dispatch->malloc_usable_size(pointer);
    520     new_pointer = g_dispatch->realloc(pointer, real_size);
    521     if (new_pointer == nullptr) {
    522       return nullptr;
    523     }
    524   }
    525 
    526   if (g_debug->config().options & FILL_ON_ALLOC) {
    527     size_t bytes = debug_malloc_usable_size(new_pointer);
    528     if (bytes > g_debug->config().fill_on_alloc_bytes) {
    529       bytes = g_debug->config().fill_on_alloc_bytes;
    530     }
    531     if (bytes > prev_size) {
    532       memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_pointer) + prev_size),
    533              g_debug->config().fill_alloc_value, bytes - prev_size);
    534     }
    535   }
    536 
    537   return new_pointer;
    538 }
    539 
    540 void* debug_calloc(size_t nmemb, size_t bytes) {
    541   if (DebugCallsDisabled()) {
    542     return g_dispatch->calloc(nmemb, bytes);
    543   }
    544 
    545   size_t size;
    546   if (__builtin_mul_overflow(nmemb, bytes, &size)) {
    547     // Overflow
    548     errno = ENOMEM;
    549     return nullptr;
    550   }
    551 
    552   if (size == 0) {
    553     size = 1;
    554   }
    555 
    556   size_t real_size;
    557   if (__builtin_add_overflow(size, g_debug->extra_bytes(), &real_size)) {
    558     // Overflow.
    559     errno = ENOMEM;
    560     return nullptr;
    561   }
    562 
    563   if (g_debug->need_header()) {
    564     // The above check will guarantee the multiply will not overflow.
    565     if (size > Header::max_size()) {
    566       errno = ENOMEM;
    567       return nullptr;
    568     }
    569 
    570     // Need to guarantee the alignment of the header.
    571     Header* header = reinterpret_cast<Header*>(
    572         g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
    573     if (header == nullptr) {
    574       return nullptr;
    575     }
    576     memset(header, 0, g_dispatch->malloc_usable_size(header));
    577     return InitHeader(header, header, size);
    578   } else {
    579     return g_dispatch->calloc(1, real_size);
    580   }
    581 }
    582 
    583 struct mallinfo debug_mallinfo() {
    584   return g_dispatch->mallinfo();
    585 }
    586 
    587 int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
    588   if (DebugCallsDisabled()) {
    589     return g_dispatch->posix_memalign(memptr, alignment, size);
    590   }
    591 
    592   if (!powerof2(alignment)) {
    593     return EINVAL;
    594   }
    595   int saved_errno = errno;
    596   *memptr = debug_memalign(alignment, size);
    597   errno = saved_errno;
    598   return (*memptr != nullptr) ? 0 : ENOMEM;
    599 }
    600 
    601 int debug_iterate(uintptr_t base, size_t size,
    602     void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
    603   // Can't allocate, malloc is disabled
    604   // Manual capture of the arguments to pass to the lambda below as void* arg
    605   struct iterate_ctx {
    606     decltype(callback) callback;
    607     decltype(arg) arg;
    608   } ctx = { callback, arg };
    609 
    610   return g_dispatch->iterate(base, size,
    611       [](uintptr_t base, size_t size, void* arg) {
    612         const iterate_ctx* ctx = reinterpret_cast<iterate_ctx*>(arg);
    613         const void* pointer = reinterpret_cast<void*>(base);
    614         if (g_debug->need_header()) {
    615           const Header* header = reinterpret_cast<const Header*>(pointer);
    616           if (g_debug->config().options & TRACK_ALLOCS) {
    617             if (g_debug->track->Contains(header)) {
    618               // Return just the body of the allocation if we're sure the header exists
    619               ctx->callback(reinterpret_cast<uintptr_t>(g_debug->GetPointer(header)),
    620                   header->usable_size, ctx->arg);
    621               return;
    622             }
    623           }
    624         }
    625         // Fall back to returning the whole allocation
    626         ctx->callback(base, size, ctx->arg);
    627       }, &ctx);
    628 }
    629 
    630 void debug_malloc_disable() {
    631   g_dispatch->malloc_disable();
    632   if (g_debug->track) {
    633     g_debug->track->PrepareFork();
    634   }
    635 }
    636 
    637 void debug_malloc_enable() {
    638   if (g_debug->track) {
    639     g_debug->track->PostForkParent();
    640   }
    641   g_dispatch->malloc_enable();
    642 }
    643 
    644 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) {
    645   if (DebugCallsDisabled() || pointer == nullptr) {
    646     return 0;
    647   }
    648 
    649   if (g_debug->need_header()) {
    650     Header* header;
    651     if (g_debug->config().options & TRACK_ALLOCS) {
    652       header = g_debug->GetHeader(pointer);
    653       if (!g_debug->track->Contains(header)) {
    654         return 0;
    655       }
    656     } else {
    657       header = reinterpret_cast<Header*>(pointer);
    658     }
    659     if (header->tag != DEBUG_TAG) {
    660       return 0;
    661     }
    662     if (g_debug->config().options & BACKTRACE) {
    663       BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
    664       if (back_header->num_frames > 0) {
    665         if (frame_count > back_header->num_frames) {
    666           frame_count = back_header->num_frames;
    667         }
    668         memcpy(frames, &back_header->frames[0], frame_count * sizeof(uintptr_t));
    669         return frame_count;
    670       }
    671     }
    672   }
    673 
    674   return 0;
    675 }
    676 
    677 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
    678 void* debug_pvalloc(size_t bytes) {
    679   if (DebugCallsDisabled()) {
    680     return g_dispatch->pvalloc(bytes);
    681   }
    682 
    683   size_t pagesize = getpagesize();
    684   size_t size = BIONIC_ALIGN(bytes, pagesize);
    685   if (size < bytes) {
    686     // Overflow
    687     errno = ENOMEM;
    688     return nullptr;
    689   }
    690   return debug_memalign(pagesize, size);
    691 }
    692 
    693 void* debug_valloc(size_t size) {
    694   if (DebugCallsDisabled()) {
    695     return g_dispatch->valloc(size);
    696   }
    697   return debug_memalign(getpagesize(), size);
    698 }
    699 #endif
    700