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 <errno.h>
30 #include <inttypes.h>
31 #include <signal.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 
38 #include <mutex>
39 #include <string>
40 #include <unordered_map>
41 #include <utility>
42 #include <vector>
43 
44 #include <android-base/stringprintf.h>
45 #include <android-base/thread_annotations.h>
46 #include <platform/bionic/macros.h>
47 
48 #include "Config.h"
49 #include "DebugData.h"
50 #include "PointerData.h"
51 #include "backtrace.h"
52 #include "debug_log.h"
53 #include "malloc_debug.h"
54 #include "UnwindBacktrace.h"
55 
56 extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
57 
58 std::atomic_uint8_t PointerData::backtrace_enabled_;
59 std::atomic_bool PointerData::backtrace_dump_;
60 
61 std::mutex PointerData::pointer_mutex_;
62 std::unordered_map<uintptr_t, PointerInfoType> PointerData::pointers_ GUARDED_BY(
63     PointerData::pointer_mutex_);
64 
65 std::mutex PointerData::frame_mutex_;
66 std::unordered_map<FrameKeyType, size_t> PointerData::key_to_index_ GUARDED_BY(
67     PointerData::frame_mutex_);
68 std::unordered_map<size_t, FrameInfoType> PointerData::frames_ GUARDED_BY(PointerData::frame_mutex_);
69 std::unordered_map<size_t, std::vector<unwindstack::LocalFrameData>> PointerData::backtraces_info_ GUARDED_BY(PointerData::frame_mutex_);
70 constexpr size_t kBacktraceEmptyIndex = 1;
71 size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_);
72 
73 std::mutex PointerData::free_pointer_mutex_;
74 std::deque<FreePointerInfoType> PointerData::free_pointers_ GUARDED_BY(
75     PointerData::free_pointer_mutex_);
76 
77 // Buffer to use for comparison.
78 static constexpr size_t kCompareBufferSize = 512 * 1024;
79 static std::vector<uint8_t> g_cmp_mem(0);
80 
ToggleBacktraceEnable(int,siginfo_t *,void *)81 static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
82   g_debug->pointer->ToggleBacktraceEnabled();
83 }
84 
EnableDump(int,siginfo_t *,void *)85 static void EnableDump(int, siginfo_t*, void*) {
86   g_debug->pointer->EnableDumping();
87 }
88 
PointerData(DebugData * debug_data)89 PointerData::PointerData(DebugData* debug_data) : OptionData(debug_data) {}
90 
Initialize(const Config & config)91 bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
92   pointers_.clear();
93   key_to_index_.clear();
94   frames_.clear();
95   free_pointers_.clear();
96   // A hash index of kBacktraceEmptyIndex indicates that we tried to get
97   // a backtrace, but there was nothing recorded.
98   cur_hash_index_ = kBacktraceEmptyIndex + 1;
99 
100   backtrace_enabled_ = config.backtrace_enabled();
101   if (config.backtrace_enable_on_signal()) {
102     struct sigaction64 enable_act = {};
103     enable_act.sa_sigaction = ToggleBacktraceEnable;
104     enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
105     if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
106       error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
107       return false;
108     }
109     if (config.options() & VERBOSE) {
110       info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
111                config.backtrace_signal(), getpid());
112     }
113   }
114 
115   if (config.options() & BACKTRACE) {
116     struct sigaction64 act = {};
117     act.sa_sigaction = EnableDump;
118     act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
119     if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
120       error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
121       return false;
122     }
123     if (config.options() & VERBOSE) {
124       info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
125                config.backtrace_dump_signal(), getpid());
126     }
127   }
128 
129   backtrace_dump_ = false;
130 
131   if (config.options() & FREE_TRACK) {
132     g_cmp_mem.resize(kCompareBufferSize, config.fill_free_value());
133   }
134   return true;
135 }
136 
AddBacktrace(size_t num_frames)137 size_t PointerData::AddBacktrace(size_t num_frames) {
138   std::vector<uintptr_t> frames;
139   std::vector<unwindstack::LocalFrameData> frames_info;
140   if (g_debug->config().options() & BACKTRACE_FULL) {
141     if (!Unwind(&frames, &frames_info, num_frames)) {
142       return kBacktraceEmptyIndex;
143     }
144   } else {
145     frames.resize(num_frames);
146     num_frames = backtrace_get(frames.data(), frames.size());
147     if (num_frames == 0) {
148       return kBacktraceEmptyIndex;
149     }
150   }
151 
152   FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
153   size_t hash_index;
154   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
155   auto entry = key_to_index_.find(key);
156   if (entry == key_to_index_.end()) {
157     frames.resize(num_frames);
158     hash_index = cur_hash_index_++;
159     key.frames = frames.data();
160     key_to_index_.emplace(key, hash_index);
161 
162     frames_.emplace(hash_index, FrameInfoType{.references = 1, .frames = std::move(frames)});
163     if (g_debug->config().options() & BACKTRACE_FULL) {
164       backtraces_info_.emplace(hash_index, std::move(frames_info));
165     }
166   } else {
167     hash_index = entry->second;
168     FrameInfoType* frame_info = &frames_[hash_index];
169     frame_info->references++;
170   }
171   return hash_index;
172 }
173 
RemoveBacktrace(size_t hash_index)174 void PointerData::RemoveBacktrace(size_t hash_index) {
175   if (hash_index <= kBacktraceEmptyIndex) {
176     return;
177   }
178 
179   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
180   auto frame_entry = frames_.find(hash_index);
181   if (frame_entry == frames_.end()) {
182     error_log("hash_index %zu does not have matching frame data.", hash_index);
183     return;
184   }
185   FrameInfoType* frame_info = &frame_entry->second;
186   if (--frame_info->references == 0) {
187     FrameKeyType key{.num_frames = frame_info->frames.size(), .frames = frame_info->frames.data()};
188     key_to_index_.erase(key);
189     frames_.erase(hash_index);
190     if (g_debug->config().options() & BACKTRACE_FULL) {
191       backtraces_info_.erase(hash_index);
192     }
193   }
194 }
195 
Add(const void * ptr,size_t pointer_size)196 void PointerData::Add(const void* ptr, size_t pointer_size) {
197   uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
198   size_t hash_index = 0;
199   if (backtrace_enabled_) {
200     hash_index = AddBacktrace(g_debug->config().backtrace_frames());
201   }
202 
203   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
204   pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
205 }
206 
Remove(const void * ptr)207 void PointerData::Remove(const void* ptr) {
208   uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
209   size_t hash_index;
210   {
211     std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
212     auto entry = pointers_.find(pointer);
213     if (entry == pointers_.end()) {
214       // Attempt to remove unknown pointer.
215       error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
216       return;
217     }
218     hash_index = entry->second.hash_index;
219     pointers_.erase(pointer);
220   }
221 
222   RemoveBacktrace(hash_index);
223 }
224 
GetFrames(const void * ptr,uintptr_t * frames,size_t max_frames)225 size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_frames) {
226   uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
227   size_t hash_index;
228   {
229     std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
230     auto entry = pointers_.find(pointer);
231     if (entry == pointers_.end()) {
232       return 0;
233     }
234     hash_index = entry->second.hash_index;
235   }
236 
237   if (hash_index <= kBacktraceEmptyIndex) {
238     return 0;
239   }
240 
241   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
242   auto frame_entry = frames_.find(hash_index);
243   if (frame_entry == frames_.end()) {
244     return 0;
245   }
246   FrameInfoType* frame_info = &frame_entry->second;
247   if (max_frames > frame_info->frames.size()) {
248     max_frames = frame_info->frames.size();
249   }
250   memcpy(frames, &frame_info->frames[0], max_frames * sizeof(uintptr_t));
251 
252   return max_frames;
253 }
254 
LogBacktrace(size_t hash_index)255 void PointerData::LogBacktrace(size_t hash_index) {
256   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
257   if (g_debug->config().options() & BACKTRACE_FULL) {
258     auto backtrace_info_entry = backtraces_info_.find(hash_index);
259     if (backtrace_info_entry != backtraces_info_.end()) {
260       UnwindLog(backtrace_info_entry->second);
261       return;
262     }
263   } else {
264     auto frame_entry = frames_.find(hash_index);
265     if (frame_entry != frames_.end()) {
266       FrameInfoType* frame_info = &frame_entry->second;
267       backtrace_log(frame_info->frames.data(), frame_info->frames.size());
268       return;
269     }
270   }
271   error_log("  hash_index %zu does not have matching frame data.", hash_index);
272 }
273 
LogFreeError(const FreePointerInfoType & info,size_t max_cmp_bytes)274 void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_bytes) {
275   error_log(LOG_DIVIDER);
276   uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
277   error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
278   uint8_t fill_free_value = g_debug->config().fill_free_value();
279   for (size_t i = 0; i < max_cmp_bytes; i++) {
280     if (memory[i] != fill_free_value) {
281       error_log("  allocation[%zu] = 0x%02x (expected 0x%02x)", i, memory[i], fill_free_value);
282     }
283   }
284 
285   if (info.hash_index > kBacktraceEmptyIndex) {
286     error_log("Backtrace at time of free:");
287     LogBacktrace(info.hash_index);
288   }
289 
290   error_log(LOG_DIVIDER);
291   if (g_debug->config().options() & ABORT_ON_ERROR) {
292     abort();
293   }
294 }
295 
VerifyFreedPointer(const FreePointerInfoType & info)296 void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
297   size_t usable_size;
298   if (g_debug->HeaderEnabled()) {
299     // Check to see if the tag data has been damaged.
300     Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(info.pointer));
301     if (header->tag != DEBUG_FREE_TAG) {
302       error_log(LOG_DIVIDER);
303       error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
304                 info.pointer, header->tag);
305       error_log(LOG_DIVIDER);
306       if (g_debug->config().options() & ABORT_ON_ERROR) {
307         abort();
308       }
309 
310       // Stop processing here, it is impossible to tell how the header
311       // may have been damaged.
312       return;
313     }
314     usable_size = header->usable_size;
315   } else {
316     usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
317   }
318 
319   size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
320                      ? usable_size
321                      : g_debug->config().fill_on_free_bytes();
322   size_t max_cmp_bytes = bytes;
323   const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.pointer);
324   while (bytes > 0) {
325     size_t bytes_to_cmp = (bytes < g_cmp_mem.size()) ? bytes : g_cmp_mem.size();
326     if (memcmp(memory, g_cmp_mem.data(), bytes_to_cmp) != 0) {
327       LogFreeError(info, max_cmp_bytes);
328     }
329     bytes -= bytes_to_cmp;
330     memory = &memory[bytes_to_cmp];
331   }
332 }
333 
AddFreed(const void * ptr)334 void* PointerData::AddFreed(const void* ptr) {
335   uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
336 
337   size_t hash_index = 0;
338   size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
339   if (num_frames) {
340     hash_index = AddBacktrace(num_frames);
341   }
342 
343   void* last = nullptr;
344   std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
345   if (free_pointers_.size() == g_debug->config().free_track_allocations()) {
346     FreePointerInfoType info(free_pointers_.front());
347     free_pointers_.pop_front();
348     VerifyFreedPointer(info);
349     RemoveBacktrace(info.hash_index);
350     last = reinterpret_cast<void*>(info.pointer);
351   }
352 
353   free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
354   return last;
355 }
356 
LogFreeBacktrace(const void * ptr)357 void PointerData::LogFreeBacktrace(const void* ptr) {
358   size_t hash_index = 0;
359   {
360     uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
361     std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
362     for (const auto& info : free_pointers_) {
363       if (info.pointer == pointer) {
364         hash_index = info.hash_index;
365         break;
366       }
367     }
368   }
369 
370   if (hash_index <= kBacktraceEmptyIndex) {
371     return;
372   }
373 
374   error_log("Backtrace of original free:");
375   LogBacktrace(hash_index);
376 }
377 
VerifyAllFreed()378 void PointerData::VerifyAllFreed() {
379   std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
380   for (auto& free_info : free_pointers_) {
381     VerifyFreedPointer(free_info);
382   }
383 }
384 
GetList(std::vector<ListInfoType> * list,bool only_with_backtrace)385 void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtrace)
386     REQUIRES(pointer_mutex_, frame_mutex_) {
387   for (const auto& entry : pointers_) {
388     FrameInfoType* frame_info = nullptr;
389     std::vector<unwindstack::LocalFrameData>* backtrace_info = nullptr;
390     size_t hash_index = entry.second.hash_index;
391     if (hash_index > kBacktraceEmptyIndex) {
392       auto frame_entry = frames_.find(hash_index);
393       if (frame_entry == frames_.end()) {
394         // Somehow wound up with a pointer with a valid hash_index, but
395         // no frame data. This should not be possible since adding a pointer
396         // occurs after the hash_index and frame data have been added.
397         // When removing a pointer, the pointer is deleted before the frame
398         // data.
399         error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
400       } else {
401         frame_info = &frame_entry->second;
402       }
403 
404       if (g_debug->config().options() & BACKTRACE_FULL) {
405         auto backtrace_entry = backtraces_info_.find(hash_index);
406         if (backtrace_entry == backtraces_info_.end()) {
407           error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
408         } else {
409           backtrace_info = &backtrace_entry->second;
410         }
411       }
412     }
413     if (hash_index == 0 && only_with_backtrace) {
414       continue;
415     }
416 
417     list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
418                                     entry.second.ZygoteChildAlloc(), frame_info, backtrace_info});
419   }
420 
421   // Sort by the size of the allocation.
422   std::sort(list->begin(), list->end(), [](const ListInfoType& a, const ListInfoType& b) {
423     // Put zygote child allocations first.
424     bool a_zygote_child_alloc = a.zygote_child_alloc;
425     bool b_zygote_child_alloc = b.zygote_child_alloc;
426     if (a_zygote_child_alloc && !b_zygote_child_alloc) {
427       return false;
428     }
429     if (!a_zygote_child_alloc && b_zygote_child_alloc) {
430       return true;
431     }
432 
433     // Sort by size, descending order.
434     if (a.size != b.size) return a.size > b.size;
435 
436     // Put pointers with no backtrace last.
437     FrameInfoType* a_frame = a.frame_info;
438     FrameInfoType* b_frame = b.frame_info;
439     if (a_frame == nullptr && b_frame != nullptr) {
440       return false;
441     } else if (a_frame != nullptr && b_frame == nullptr) {
442       return true;
443     } else if (a_frame == nullptr && b_frame == nullptr) {
444       return a.pointer < b.pointer;
445     }
446 
447     // Put the pointers with longest backtrace first.
448     if (a_frame->frames.size() != b_frame->frames.size()) {
449       return a_frame->frames.size() > b_frame->frames.size();
450     }
451 
452     // Last sort by pointer.
453     return a.pointer < b.pointer;
454   });
455 }
456 
GetUniqueList(std::vector<ListInfoType> * list,bool only_with_backtrace)457 void PointerData::GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace)
458     REQUIRES(pointer_mutex_, frame_mutex_) {
459   GetList(list, only_with_backtrace);
460 
461   // Remove duplicates of size/backtraces.
462   for (auto iter = list->begin(); iter != list->end();) {
463     auto dup_iter = iter + 1;
464     bool zygote_child_alloc = iter->zygote_child_alloc;
465     size_t size = iter->size;
466     FrameInfoType* frame_info = iter->frame_info;
467     for (; dup_iter != list->end(); ++dup_iter) {
468       if (zygote_child_alloc != dup_iter->zygote_child_alloc || size != dup_iter->size ||
469           frame_info != dup_iter->frame_info) {
470         break;
471       }
472       iter->num_allocations++;
473     }
474     iter = list->erase(iter + 1, dup_iter);
475   }
476 }
477 
LogLeaks()478 void PointerData::LogLeaks() {
479   std::vector<ListInfoType> list;
480 
481   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
482   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
483   GetList(&list, false);
484 
485   size_t track_count = 0;
486   for (const auto& list_info : list) {
487     error_log("+++ %s leaked block of size %zu at 0x%" PRIxPTR " (leak %zu of %zu)", getprogname(),
488               list_info.size, list_info.pointer, ++track_count, list.size());
489     if (list_info.backtrace_info != nullptr) {
490       error_log("Backtrace at time of allocation:");
491       UnwindLog(*list_info.backtrace_info);
492     } else if (list_info.frame_info != nullptr) {
493       error_log("Backtrace at time of allocation:");
494       backtrace_log(list_info.frame_info->frames.data(), list_info.frame_info->frames.size());
495     }
496     // Do not bother to free the pointers, we are about to exit any way.
497   }
498 }
499 
GetAllocList(std::vector<ListInfoType> * list)500 void PointerData::GetAllocList(std::vector<ListInfoType>* list) {
501   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
502   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
503 
504   if (pointers_.empty()) {
505     return;
506   }
507 
508   GetList(list, false);
509 }
510 
GetInfo(uint8_t ** info,size_t * overall_size,size_t * info_size,size_t * total_memory,size_t * backtrace_size)511 void PointerData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
512                           size_t* total_memory, size_t* backtrace_size) {
513   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
514   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
515 
516   if (pointers_.empty()) {
517     return;
518   }
519 
520   std::vector<ListInfoType> list;
521   GetUniqueList(&list, true);
522   if (list.empty()) {
523     return;
524   }
525 
526   *backtrace_size = g_debug->config().backtrace_frames();
527   *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
528   *overall_size = *info_size * list.size();
529   *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, list.size()));
530   if (*info == nullptr) {
531     return;
532   }
533 
534   uint8_t* data = *info;
535   *total_memory = 0;
536   for (const auto& list_info : list) {
537     FrameInfoType* frame_info = list_info.frame_info;
538     *total_memory += list_info.size * list_info.num_allocations;
539     size_t allocation_size =
540         PointerInfoType::GetEncodedSize(list_info.zygote_child_alloc, list_info.size);
541     memcpy(data, &allocation_size, sizeof(size_t));
542     memcpy(&data[sizeof(size_t)], &list_info.num_allocations, sizeof(size_t));
543     if (frame_info != nullptr) {
544       memcpy(&data[2 * sizeof(size_t)], frame_info->frames.data(),
545              frame_info->frames.size() * sizeof(uintptr_t));
546     }
547     data += *info_size;
548   }
549 }
550 
Exists(const void * ptr)551 bool PointerData::Exists(const void* ptr) {
552   uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
553   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
554   return pointers_.count(pointer) != 0;
555 }
556 
DumpLiveToFile(int fd)557 void PointerData::DumpLiveToFile(int fd) {
558   std::vector<ListInfoType> list;
559 
560   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
561   std::lock_guard<std::mutex> frame_guard(frame_mutex_);
562   GetUniqueList(&list, false);
563 
564   size_t total_memory = 0;
565   for (const auto& info : list) {
566     total_memory += info.size * info.num_allocations;
567   }
568 
569   dprintf(fd, "Total memory: %zu\n", total_memory);
570   dprintf(fd, "Allocation records: %zd\n", list.size());
571   dprintf(fd, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
572   dprintf(fd, "\n");
573 
574   for (const auto& info : list) {
575     dprintf(fd, "z %d  sz %8zu  num    %zu  bt", (info.zygote_child_alloc) ? 1 : 0, info.size,
576             info.num_allocations);
577     FrameInfoType* frame_info = info.frame_info;
578     if (frame_info != nullptr) {
579       for (size_t i = 0; i < frame_info->frames.size(); i++) {
580         if (frame_info->frames[i] == 0) {
581           break;
582         }
583         dprintf(fd, " %" PRIxPTR, frame_info->frames[i]);
584       }
585     }
586     dprintf(fd, "\n");
587     if (info.backtrace_info != nullptr) {
588       dprintf(fd, "  bt_info");
589       for (const auto& frame : *info.backtrace_info) {
590         dprintf(fd, " {");
591         if (frame.map_info != nullptr && !frame.map_info->name().empty()) {
592           dprintf(fd, "\"%s\"", frame.map_info->name().c_str());
593         } else {
594           dprintf(fd, "\"\"");
595         }
596         dprintf(fd, " %" PRIx64, frame.rel_pc);
597         if (frame.function_name.empty()) {
598           dprintf(fd, " \"\" 0}");
599         } else {
600           char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr,
601                                                 nullptr);
602           const char* name;
603           if (demangled_name != nullptr) {
604             name = demangled_name;
605           } else {
606             name = frame.function_name.c_str();
607           }
608           dprintf(fd, " \"%s\" %" PRIx64 "}", name, frame.function_offset);
609           free(demangled_name);
610         }
611       }
612       dprintf(fd, "\n");
613     }
614   }
615 }
616 
PrepareFork()617 void PointerData::PrepareFork() NO_THREAD_SAFETY_ANALYSIS {
618   free_pointer_mutex_.lock();
619   pointer_mutex_.lock();
620   frame_mutex_.lock();
621 }
622 
PostForkParent()623 void PointerData::PostForkParent() NO_THREAD_SAFETY_ANALYSIS {
624   frame_mutex_.unlock();
625   pointer_mutex_.unlock();
626   free_pointer_mutex_.unlock();
627 }
628 
PostForkChild()629 void PointerData::PostForkChild() __attribute__((no_thread_safety_analysis)) {
630   // Make sure that any potential mutexes have been released and are back
631   // to an initial state.
632   frame_mutex_.try_lock();
633   frame_mutex_.unlock();
634   pointer_mutex_.try_lock();
635   pointer_mutex_.unlock();
636   free_pointer_mutex_.try_lock();
637   free_pointer_mutex_.unlock();
638 }
639