1 /* 2 * Copyright (C) 2015 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 <pthread.h> 30 #include <stdint.h> 31 #include <stdlib.h> 32 33 #include <algorithm> 34 #include <vector> 35 36 #include <private/ScopedPthreadMutexLocker.h> 37 38 #include "backtrace.h" 39 #include "BacktraceData.h" 40 #include "Config.h" 41 #include "DebugData.h" 42 #include "debug_disable.h" 43 #include "debug_log.h" 44 #include "malloc_debug.h" 45 #include "TrackData.h" 46 47 void TrackData::GetList(std::vector<const Header*>* list) { 48 ScopedDisableDebugCalls disable; 49 50 for (const auto& header : headers_) { 51 list->push_back(header); 52 } 53 54 // Sort by the size of the allocation. 55 std::sort(list->begin(), list->end(), [](const Header* a, const Header* b) { 56 if (a->size == b->size) return a < b; 57 return a->size > b->size; 58 }); 59 } 60 61 void TrackData::Add(const Header* header, bool backtrace_found) { 62 ScopedDisableDebugCalls disable; 63 64 pthread_mutex_lock(&mutex_); 65 if (backtrace_found) { 66 total_backtrace_allocs_++; 67 } 68 headers_.insert(header); 69 pthread_mutex_unlock(&mutex_); 70 } 71 72 void TrackData::Remove(const Header* header, bool backtrace_found) { 73 ScopedDisableDebugCalls disable; 74 75 pthread_mutex_lock(&mutex_); 76 headers_.erase(header); 77 if (backtrace_found) { 78 total_backtrace_allocs_--; 79 } 80 pthread_mutex_unlock(&mutex_); 81 } 82 83 bool TrackData::Contains(const Header* header) { 84 ScopedDisableDebugCalls disable; 85 86 pthread_mutex_lock(&mutex_); 87 bool found = headers_.count(header); 88 pthread_mutex_unlock(&mutex_); 89 return found; 90 } 91 92 void TrackData::DisplayLeaks(DebugData& debug) { 93 ScopedDisableDebugCalls disable; 94 95 std::vector<const Header*> list; 96 GetList(&list); 97 98 size_t track_count = 0; 99 for (const auto& header : list) { 100 error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(), 101 header->real_size(), debug.GetPointer(header), ++track_count, list.size()); 102 if (debug.config().options & BACKTRACE) { 103 BacktraceHeader* back_header = debug.GetAllocBacktrace(header); 104 if (back_header->num_frames > 0) { 105 error_log("Backtrace at time of allocation:"); 106 backtrace_log(&back_header->frames[0], back_header->num_frames); 107 } 108 } 109 g_dispatch->free(header->orig_pointer); 110 } 111 } 112 113 void TrackData::GetInfo(DebugData& debug, uint8_t** info, size_t* overall_size, 114 size_t* info_size, size_t* total_memory, size_t* backtrace_size) { 115 ScopedPthreadMutexLocker scoped(&mutex_); 116 117 if (headers_.size() == 0 || total_backtrace_allocs_ == 0) { 118 return; 119 } 120 121 *backtrace_size = debug.config().backtrace_frames; 122 *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size; 123 *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_)); 124 if (*info == nullptr) { 125 return; 126 } 127 *overall_size = *info_size * total_backtrace_allocs_; 128 129 std::vector<const Header*> list; 130 GetList(&list); 131 132 uint8_t* data = *info; 133 for (const auto& header : list) { 134 BacktraceHeader* back_header = debug.GetAllocBacktrace(header); 135 if (back_header->num_frames > 0) { 136 memcpy(data, &header->size, sizeof(size_t)); 137 memcpy(&data[sizeof(size_t)], &back_header->num_frames, sizeof(size_t)); 138 memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0], 139 back_header->num_frames * sizeof(uintptr_t)); 140 141 *total_memory += header->real_size(); 142 143 data += *info_size; 144 } 145 } 146 } 147