blob: 4266aa282913bf62e770fe20fe4b2d5976cc44c3 [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
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
Christopher Ferris55a89a42016-04-07 17:14:53 -070047TrackData::TrackData(DebugData* debug_data) : OptionData(debug_data) {
48}
Christopher Ferris63860cb2015-11-16 17:30:32 -080049
Christopher Ferris55a89a42016-04-07 17:14:53 -070050void TrackData::GetList(std::vector<const Header*>* list) {
Christopher Ferris63860cb2015-11-16 17:30:32 -080051 for (const auto& header : headers_) {
52 list->push_back(header);
53 }
54
55 // Sort by the size of the allocation.
Colin Cross869691c2016-01-29 12:48:18 -080056 std::sort(list->begin(), list->end(), [](const Header* a, const Header* b) {
Christopher Ferris63860cb2015-11-16 17:30:32 -080057 if (a->size == b->size) return a < b;
58 return a->size > b->size;
59 });
60}
61
Christopher Ferris602b88c2017-08-04 13:04:04 -070062void TrackData::GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory) {
63 if (!(debug_->config().options() & BACKTRACE)) {
64 return;
65 }
66
67 *total_memory = 0;
68 for (const auto& header : headers_) {
69 list->push_back(header);
70 *total_memory += header->real_size();
71 }
72
73 // Put all zygote allocations first by size and backtrace.
74 // Then all zygote child allocation by size and backtrace.
75 std::sort(list->begin(), list->end(), [&](const Header* a, const Header* b) {
76 if (a->zygote_child_alloc() && !b->zygote_child_alloc()) {
77 return false;
78 } else if (!a->zygote_child_alloc() && b->zygote_child_alloc()) {
79 return true;
80 }
81 if (a->real_size() != b->real_size()) return a->real_size() < b->real_size();
82 // If the size is the same, compare backtrace elements.
83 BacktraceHeader* a_back = debug_->GetAllocBacktrace(a);
84 BacktraceHeader* b_back = debug_->GetAllocBacktrace(b);
85 for (size_t i = 0; i < a_back->num_frames; i++) {
86 if (i > b_back->num_frames) {
87 // All frames equal up to this point, but a has more frames available.
88 return false;
89 }
90 if (a_back->frames[i] < b_back->frames[i]) {
91 return false;
92 } else if (a_back->frames[i] > b_back->frames[i]) {
93 return true;
94 }
95 }
96 if (a_back->num_frames < b_back->num_frames) {
97 // All frames equal up to this point, but b has more frames available.
98 return true;
99 }
100 return false;
101 });
102
103}
104
Colin Cross869691c2016-01-29 12:48:18 -0800105void TrackData::Add(const Header* header, bool backtrace_found) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800106 pthread_mutex_lock(&mutex_);
107 if (backtrace_found) {
108 total_backtrace_allocs_++;
109 }
110 headers_.insert(header);
111 pthread_mutex_unlock(&mutex_);
112}
113
Colin Cross869691c2016-01-29 12:48:18 -0800114void TrackData::Remove(const Header* header, bool backtrace_found) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800115 pthread_mutex_lock(&mutex_);
116 headers_.erase(header);
117 if (backtrace_found) {
118 total_backtrace_allocs_--;
119 }
120 pthread_mutex_unlock(&mutex_);
121}
122
Colin Cross869691c2016-01-29 12:48:18 -0800123bool TrackData::Contains(const Header* header) {
Colin Cross869691c2016-01-29 12:48:18 -0800124 pthread_mutex_lock(&mutex_);
125 bool found = headers_.count(header);
126 pthread_mutex_unlock(&mutex_);
127 return found;
128}
129
Christopher Ferris55a89a42016-04-07 17:14:53 -0700130void TrackData::DisplayLeaks() {
Colin Cross869691c2016-01-29 12:48:18 -0800131 std::vector<const Header*> list;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800132 GetList(&list);
133
134 size_t track_count = 0;
135 for (const auto& header : list) {
136 error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(),
Christopher Ferris55a89a42016-04-07 17:14:53 -0700137 header->real_size(), debug_->GetPointer(header), ++track_count, list.size());
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700138 if (debug_->config().options() & BACKTRACE) {
Christopher Ferris55a89a42016-04-07 17:14:53 -0700139 BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800140 if (back_header->num_frames > 0) {
141 error_log("Backtrace at time of allocation:");
142 backtrace_log(&back_header->frames[0], back_header->num_frames);
143 }
144 }
145 g_dispatch->free(header->orig_pointer);
146 }
147}
148
Christopher Ferris55a89a42016-04-07 17:14:53 -0700149void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
150 size_t* total_memory, size_t* backtrace_size) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800151 ScopedPthreadMutexLocker scoped(&mutex_);
152
153 if (headers_.size() == 0 || total_backtrace_allocs_ == 0) {
154 return;
155 }
156
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700157 *backtrace_size = debug_->config().backtrace_frames();
Christopher Ferris63860cb2015-11-16 17:30:32 -0800158 *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
159 *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
160 if (*info == nullptr) {
161 return;
162 }
163 *overall_size = *info_size * total_backtrace_allocs_;
164
Colin Cross869691c2016-01-29 12:48:18 -0800165 std::vector<const Header*> list;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800166 GetList(&list);
167
168 uint8_t* data = *info;
Christopher Ferris426b00a2017-03-09 13:47:37 -0800169 size_t num_allocations = 1;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800170 for (const auto& header : list) {
Christopher Ferris55a89a42016-04-07 17:14:53 -0700171 BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800172 if (back_header->num_frames > 0) {
173 memcpy(data, &header->size, sizeof(size_t));
Christopher Ferris426b00a2017-03-09 13:47:37 -0800174 memcpy(&data[sizeof(size_t)], &num_allocations, sizeof(size_t));
Christopher Ferris63860cb2015-11-16 17:30:32 -0800175 memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0],
176 back_header->num_frames * sizeof(uintptr_t));
177
178 *total_memory += header->real_size();
179
180 data += *info_size;
181 }
182 }
183}