aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/malloc_debug/BacktraceData.cpp29
-rw-r--r--libc/malloc_debug/BacktraceData.h16
-rw-r--r--libc/malloc_debug/Config.cpp45
-rw-r--r--libc/malloc_debug/Config.h8
-rw-r--r--libc/malloc_debug/README.md91
-rw-r--r--libc/malloc_debug/TrackData.cpp43
-rw-r--r--libc/malloc_debug/TrackData.h2
-rw-r--r--libc/malloc_debug/exported32.map1
-rw-r--r--libc/malloc_debug/exported64.map1
-rw-r--r--libc/malloc_debug/malloc_debug.cpp93
-rw-r--r--libc/malloc_debug/malloc_debug.h3
-rw-r--r--libc/malloc_debug/tests/malloc_debug_config_tests.cpp55
-rw-r--r--libc/malloc_debug/tests/malloc_debug_unit_tests.cpp231
13 files changed, 594 insertions, 24 deletions
diff --git a/libc/malloc_debug/BacktraceData.cpp b/libc/malloc_debug/BacktraceData.cpp
index 752d50713..65ae6fafa 100644
--- a/libc/malloc_debug/BacktraceData.cpp
+++ b/libc/malloc_debug/BacktraceData.cpp
@@ -41,12 +41,12 @@
#include "debug_log.h"
#include "malloc_debug.h"
-static void EnableToggle(int, siginfo_t*, void*) {
- if (g_debug->backtrace->enabled()) {
- g_debug->backtrace->set_enabled(false);
- } else {
- g_debug->backtrace->set_enabled(true);
- }
+static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
+ g_debug->backtrace->ToggleBacktraceEnabled();
+}
+
+static void EnableDump(int, siginfo_t*, void*) {
+ g_debug->backtrace->EnableDumping();
}
BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t* offset)
@@ -62,7 +62,7 @@ bool BacktraceData::Initialize(const Config& config) {
struct sigaction enable_act;
memset(&enable_act, 0, sizeof(enable_act));
- enable_act.sa_sigaction = EnableToggle;
+ enable_act.sa_sigaction = ToggleBacktraceEnable;
enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&enable_act.sa_mask);
if (sigaction(config.backtrace_signal(), &enable_act, nullptr) != 0) {
@@ -72,5 +72,20 @@ bool BacktraceData::Initialize(const Config& config) {
info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
config.backtrace_signal(), getpid());
}
+
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+
+ act.sa_sigaction = EnableDump;
+ act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(config.backtrace_dump_signal(), &act, nullptr) != 0) {
+ error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
+ return false;
+ }
+ info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+ config.backtrace_dump_signal(), getpid());
+
+ dump_ = false;
return true;
}
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
index 6dee505e2..c8234dc3c 100644
--- a/libc/malloc_debug/BacktraceData.h
+++ b/libc/malloc_debug/BacktraceData.h
@@ -31,6 +31,8 @@
#include <stdint.h>
+#include <atomic>
+
#include <private/bionic_macros.h>
#include "OptionData.h"
@@ -47,13 +49,21 @@ class BacktraceData : public OptionData {
inline size_t alloc_offset() { return alloc_offset_; }
- bool enabled() { return enabled_; }
- void set_enabled(bool enabled) { enabled_ = enabled; }
+ bool ShouldBacktrace() { return enabled_ == 1; }
+ void ToggleBacktraceEnabled() { enabled_.fetch_xor(1); }
+
+ void EnableDumping() { dump_ = true; }
+ bool ShouldDumpAndReset() {
+ bool expected = true;
+ return dump_.compare_exchange_strong(expected, false);
+ }
private:
size_t alloc_offset_ = 0;
- volatile bool enabled_ = false;
+ std::atomic_uint8_t enabled_;
+
+ std::atomic_bool dump_;
DISALLOW_COPY_AND_ASSIGN(BacktraceData);
};
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index df453a930..e3798ab9f 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -56,6 +56,7 @@ static constexpr size_t MAX_GUARD_BYTES = 16384;
static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16;
static constexpr size_t MAX_BACKTRACE_FRAMES = 256;
+static constexpr const char DEFAULT_BACKTRACE_DUMP_PREFIX[] = "/data/local/tmp/backtrace_heap";
static constexpr size_t DEFAULT_EXPAND_BYTES = 16;
static constexpr size_t MAX_EXPAND_BYTES = 16384;
@@ -85,6 +86,13 @@ const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
{BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
},
+ {"backtrace_dump_on_exit",
+ {0, &Config::SetBacktraceDumpOnExit},
+ },
+ {"backtrace_dump_prefix",
+ {0, &Config::SetBacktraceDumpPrefix},
+ },
+
{"fill",
{FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
},
@@ -236,6 +244,24 @@ bool Config::SetBacktraceEnableOnSignal(const std::string& option, const std::st
&backtrace_frames_);
}
+bool Config::SetBacktraceDumpOnExit(const std::string& option, const std::string& value) {
+ if (Config::VerifyValueEmpty(option, value)) {
+ backtrace_dump_on_exit_ = true;
+ return true;
+ }
+ return false;
+}
+
+bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value) {
+ if (value.empty()) {
+ backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
+ } else {
+ backtrace_dump_prefix_ = value;
+ }
+ return true;
+}
+
+
bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
}
@@ -309,6 +335,9 @@ void Config::LogUsage() const {
error_log(" backtrace[=XX]");
error_log(" Enable capturing the backtrace at the point of allocation.");
error_log(" If XX is set it sets the number of backtrace frames.");
+ error_log(" This option also enables dumping the backtrace heap data");
+ error_log(" when a signal is received. The data is dumped to the file");
+ error_log(" backtrace_dump_prefix.<PID>.txt.");
error_log(" The default is %zu frames, the max number of frames is %zu.",
DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
error_log("");
@@ -319,6 +348,19 @@ void Config::LogUsage() const {
error_log(" frames. The default is %zu frames, the max number of frames is %zu.",
DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
error_log("");
+ error_log(" backtrace_dump_prefix[=FILE]");
+ error_log(" This option only has meaning if the backtrace option has been specified.");
+ error_log(" This is the prefix of the name of the file to which backtrace heap");
+ error_log(" data will be dumped. The file will be named backtrace_dump_prefix.<PID>.txt.");
+ error_log(" The default is %s.", DEFAULT_BACKTRACE_DUMP_PREFIX);
+
+ error_log("");
+ error_log(" backtrace_dump_on_exit");
+ error_log(" This option only has meaning if the backtrace option has been specified.");
+ error_log(" This will cause all live allocations to be dumped to the file");
+ error_log(" backtrace_dump_prefix.<PID>.final.txt.");
+ error_log(" The default is false.");
+ error_log("");
error_log(" fill_on_alloc[=XX]");
error_log(" On first allocation, fill with the value 0x%02x.", DEFAULT_FILL_ALLOC_VALUE);
error_log(" If XX is set it will only fill up to XX bytes of the");
@@ -426,12 +468,15 @@ bool Config::Init(const char* options_str) {
front_guard_value_ = DEFAULT_FRONT_GUARD_VALUE;
rear_guard_value_ = DEFAULT_REAR_GUARD_VALUE;
backtrace_signal_ = SIGRTMAX - 19;
+ backtrace_dump_signal_ = SIGRTMAX - 17;
record_allocs_signal_ = SIGRTMAX - 18;
free_track_backtrace_num_frames_ = 0;
record_allocs_file_.clear();
fill_on_free_bytes_ = 0;
backtrace_enable_on_signal_ = false;
backtrace_enabled_ = false;
+ backtrace_dump_on_exit_ = false;
+ backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
// Process each option name we can find.
std::string option;
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index d8a706925..349ad775d 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -65,9 +65,12 @@ class Config {
uint64_t options() const { return options_; }
int backtrace_signal() const { return backtrace_signal_; }
+ int backtrace_dump_signal() const { return backtrace_dump_signal_; }
size_t backtrace_frames() const { return backtrace_frames_; }
size_t backtrace_enabled() const { return backtrace_enabled_; }
size_t backtrace_enable_on_signal() const { return backtrace_enable_on_signal_; }
+ bool backtrace_dump_on_exit() const { return backtrace_dump_on_exit_; }
+ const std::string& backtrace_dump_prefix() const { return backtrace_dump_prefix_; }
size_t front_guard_bytes() const { return front_guard_bytes_; }
size_t rear_guard_bytes() const { return rear_guard_bytes_; }
@@ -110,6 +113,8 @@ class Config {
bool SetBacktrace(const std::string& option, const std::string& value);
bool SetBacktraceEnableOnSignal(const std::string& option, const std::string& value);
+ bool SetBacktraceDumpOnExit(const std::string& option, const std::string& value);
+ bool SetBacktraceDumpPrefix(const std::string& option, const std::string& value);
bool SetExpandAlloc(const std::string& option, const std::string& value);
@@ -130,8 +135,11 @@ class Config {
bool backtrace_enable_on_signal_ = false;
int backtrace_signal_ = 0;
+ int backtrace_dump_signal_ = 0;
bool backtrace_enabled_ = false;
size_t backtrace_frames_ = 0;
+ bool backtrace_dump_on_exit_ = false;
+ std::string backtrace_dump_prefix_;
size_t fill_on_alloc_bytes_ = 0;
size_t fill_on_free_bytes_ = 0;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 03a8a73e5..bb56cb8bb 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -108,6 +108,17 @@ this can be set to is 256.
This option adds a special header to all allocations that contains the
backtrace and information about the original allocation.
+As of P, this option will also enable dumping backtrace heap data to a
+file when the process receives the signal SIGRTMAX - 17 ( which is 47 on most
+Android devices). The format of this dumped data is the same format as
+that dumped when running am dumpheap -n. The default is to dump this data
+to the file /data/local/tmp/backtrace\_heap.**PID**.txt. This is useful when
+used with native only executables that run for a while since these processes
+are not spawned from a zygote process.
+
+Note that when the signal is received, the heap is not dumped until the next
+malloc/free occurs.
+
### backtrace\_enable\_on\_signal[=MAX\_FRAMES]
Enable capturing the backtrace of each allocation site. If the
backtrace capture is toggled when the process receives the signal
@@ -123,6 +134,26 @@ this can be set to is 256.
This option adds a special header to all allocations that contains the
backtrace and information about the original allocation.
+### backtrace\_dump\_on\_exit
+As of P, when the backtrace option has been enabled, this causes the backtrace
+dump heap data to be dumped to a file when the program exits. If the backtrace
+option has not been enabled, this does nothing. The default is to dump this
+to the file named /data/local/tmp/backtrace\_heap.**PID**.exit.txt.
+
+The file location can be changed by setting the backtrace\_dump\_prefix
+option.
+
+### backtrace\_dump\_prefix
+As of P, when the backtrace options has been enabled, this sets the prefix
+used for dumping files when the signal SIGRTMAX - 17 is received or when
+the program exits and backtrace\_dump\_on\_exit is set.
+
+The default is /data/local/tmp/backtrace\_heap.
+
+When this value is changed from the default, then the filename chosen
+on the signal will be backtrace\_dump\_prefix.**PID**.txt. The filename chosen
+when the program exits will be backtrace\_dump\_prefix.**PID**.exit.txt.
+
### fill\_on\_alloc[=MAX\_FILLED\_BYTES]
Any allocation routine, other than calloc, will result in the allocation being
filled with the value 0xeb. When doing a realloc to a larger size, the bytes
@@ -369,6 +400,66 @@ the pointer has been corrupted.
As with the other error message, the function in parenthesis is the
function that was called with the bad pointer.
+Backtrace Heap Dump Format
+==========================
+
+This section describes the format of the backtrace heap dump. This data is
+generated by am dumpheap -n or, as of P, by the signal or on exit.
+
+The data has this header:
+
+ Android Native Heap Dump v1.0
+
+ Total memory: XXXX
+ Allocation records: YYYY
+ Backtrace size: ZZZZ
+
+Total memory is the total of all of the currently live allocations.
+Allocation records is the total number of allocation records.
+Backtrace size is the maximum number of backtrace frames that can be present.
+
+Following this header are two different sections, the first section is the
+allocation records, the second section is the map data.
+
+The allocation record data has this format:
+
+ z ZYGOTE_CHILD_ALLOC sz ALLOCATION_SIZE num NUM_ALLOCATIONS bt FRAMES
+
+ZYGOTE\_CHILD\_ALLOC is either 0 or 1. 0 means this was allocated by the
+zygote process or in a process not spawned from the zygote. 1 means this
+was allocated by an application after it forked off from the zygote process.
+
+ALLOCATION\_SIZE is the size of the allocation.
+NUM\_ALLOCATIONS is the number of allocations that have this size and have the
+same backtrace.
+FRAMES is a list of instruction pointers that represent the backtrace of the
+allocation.
+
+Example:
+
+ z 0 sz 400 num 1 bt 0000a230 0000b500
+ z 1 sz 500 num 3 bt 0000b000 0000c000
+
+The first allocation record was created by the zygote of size 400 only one
+with this backtrace/size and a backtrace of 0xa230, 0xb500.
+The second allocation record was create by an application spawned from the
+zygote of size 500, where there are three of these allocation with the same
+backtrace/size and a backtrace of 0xb000, 0xc000.
+
+The final section is the map data for the process:
+
+ MAPS
+ 7fe9181000-7fe91a2000 rw-p 00000000 00:00 0 /system/lib/libc.so
+ .
+ .
+ .
+ END
+
+The map data is simply the output of /proc/PID/maps. This data can be used to
+decode the frames in the backtraces.
+
+There is a tool to visualize this data, development/scripts/native\_heapdump\_viewer.py.
+
Examples
========
diff --git a/libc/malloc_debug/TrackData.cpp b/libc/malloc_debug/TrackData.cpp
index 7ce477cff..4266aa282 100644
--- a/libc/malloc_debug/TrackData.cpp
+++ b/libc/malloc_debug/TrackData.cpp
@@ -59,6 +59,49 @@ void TrackData::GetList(std::vector<const Header*>* list) {
});
}
+void TrackData::GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory) {
+ if (!(debug_->config().options() & BACKTRACE)) {
+ return;
+ }
+
+ *total_memory = 0;
+ for (const auto& header : headers_) {
+ list->push_back(header);
+ *total_memory += header->real_size();
+ }
+
+ // Put all zygote allocations first by size and backtrace.
+ // Then all zygote child allocation by size and backtrace.
+ std::sort(list->begin(), list->end(), [&](const Header* a, const Header* b) {
+ if (a->zygote_child_alloc() && !b->zygote_child_alloc()) {
+ return false;
+ } else if (!a->zygote_child_alloc() && b->zygote_child_alloc()) {
+ return true;
+ }
+ if (a->real_size() != b->real_size()) return a->real_size() < b->real_size();
+ // If the size is the same, compare backtrace elements.
+ BacktraceHeader* a_back = debug_->GetAllocBacktrace(a);
+ BacktraceHeader* b_back = debug_->GetAllocBacktrace(b);
+ for (size_t i = 0; i < a_back->num_frames; i++) {
+ if (i > b_back->num_frames) {
+ // All frames equal up to this point, but a has more frames available.
+ return false;
+ }
+ if (a_back->frames[i] < b_back->frames[i]) {
+ return false;
+ } else if (a_back->frames[i] > b_back->frames[i]) {
+ return true;
+ }
+ }
+ if (a_back->num_frames < b_back->num_frames) {
+ // All frames equal up to this point, but b has more frames available.
+ return true;
+ }
+ return false;
+ });
+
+}
+
void TrackData::Add(const Header* header, bool backtrace_found) {
pthread_mutex_lock(&mutex_);
if (backtrace_found) {
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
index e4c8951e3..f7486e9d6 100644
--- a/libc/malloc_debug/TrackData.h
+++ b/libc/malloc_debug/TrackData.h
@@ -51,6 +51,8 @@ class TrackData : public OptionData {
void GetList(std::vector<const Header*>* list);
+ void GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory);
+
void Add(const Header* header, bool backtrace_found);
void Remove(const Header* header, bool backtrace_found);
diff --git a/libc/malloc_debug/exported32.map b/libc/malloc_debug/exported32.map
index 59bb10283..e92a7cfc8 100644
--- a/libc/malloc_debug/exported32.map
+++ b/libc/malloc_debug/exported32.map
@@ -1,6 +1,7 @@
LIBC_MALLOC_DEBUG {
global:
debug_calloc;
+ debug_dump_heap;
debug_finalize;
debug_free;
debug_free_malloc_leak_info;
diff --git a/libc/malloc_debug/exported64.map b/libc/malloc_debug/exported64.map
index ec9d84095..94104b0ca 100644
--- a/libc/malloc_debug/exported64.map
+++ b/libc/malloc_debug/exported64.map
@@ -1,6 +1,7 @@
LIBC_MALLOC_DEBUG {
global:
debug_calloc;
+ debug_dump_heap;
debug_finalize;
debug_free;
debug_free_malloc_leak_info;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 014d3855e..d890a1ccd 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -34,8 +34,11 @@
#include <sys/param.h>
#include <unistd.h>
+#include <mutex>
#include <vector>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <private/bionic_malloc_dispatch.h>
#include "backtrace.h"
@@ -65,6 +68,7 @@ __BEGIN_DECLS
bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
const char* options);
void debug_finalize();
+bool debug_dump_heap(const char* file_name);
void debug_get_malloc_leak_info(
uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
size_t* backtrace_size);
@@ -138,7 +142,7 @@ static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
header->orig_pointer = orig_pointer;
header->size = size;
if (*g_malloc_zygote_child) {
- header->set_zygote();
+ header->set_zygote_child_alloc();
}
header->usable_size = g_dispatch->malloc_usable_size(orig_pointer);
if (header->usable_size == 0) {
@@ -164,7 +168,7 @@ static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
bool backtrace_found = false;
if (g_debug->config().options() & BACKTRACE) {
BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
- if (g_debug->backtrace->enabled()) {
+ if (g_debug->backtrace->ShouldBacktrace()) {
back_header->num_frames = backtrace_get(
&back_header->frames[0], g_debug->config().backtrace_frames());
backtrace_found = back_header->num_frames > 0;
@@ -224,6 +228,13 @@ void debug_finalize() {
g_debug->track->DisplayLeaks();
}
+ if ((g_debug->config().options() & BACKTRACE) && g_debug->config().backtrace_dump_on_exit()) {
+ ScopedDisableDebugCalls disable;
+ debug_dump_heap(
+ android::base::StringPrintf("%s.%d.exit.txt",
+ g_debug->config().backtrace_dump_prefix().c_str(), getpid()).c_str());
+ }
+
DebugDisableSet(true);
backtrace_shutdown();
@@ -288,6 +299,13 @@ size_t debug_malloc_usable_size(void* pointer) {
}
static void *internal_malloc(size_t size) {
+ if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
+ debug_dump_heap(
+ android::base::StringPrintf("%s.%d.txt",
+ g_debug->config().backtrace_dump_prefix().c_str(),
+ getpid()).c_str());
+ }
+
if (size == 0) {
size = 1;
}
@@ -341,6 +359,13 @@ void* debug_malloc(size_t size) {
}
static void internal_free(void* pointer) {
+ if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
+ debug_dump_heap(
+ android::base::StringPrintf("%s.%d.txt",
+ g_debug->config().backtrace_dump_prefix().c_str(),
+ getpid()).c_str());
+ }
+
void* free_pointer = pointer;
size_t bytes;
Header* header;
@@ -538,7 +563,7 @@ void* debug_realloc(void* pointer, size_t bytes) {
if (real_size < header->usable_size) {
header->size = real_size;
if (*g_malloc_zygote_child) {
- header->set_zygote();
+ header->set_zygote_child_alloc();
}
if (g_debug->config().options() & REAR_GUARD) {
// Don't bother allocating a smaller pointer in this case, simply
@@ -758,3 +783,65 @@ void* debug_valloc(size_t size) {
return debug_memalign(getpagesize(), size);
}
#endif
+
+static std::mutex g_dump_lock;
+
+bool debug_dump_heap(const char* file_name) {
+ ScopedDisableDebugCalls disable;
+
+ std::lock_guard<std::mutex> guard(g_dump_lock);
+
+ FILE* fp = fopen(file_name, "w+e");
+ if (fp == nullptr) {
+ error_log("Unable to create file: %s", file_name);
+ return false;
+ }
+ error_log("Dumping to file: %s\n", file_name);
+
+ if (!(g_debug->config().options() & BACKTRACE)) {
+ fprintf(fp, "Native heap dump not available. To enable, run these commands (requires root):\n");
+ fprintf(fp, "# adb shell stop\n");
+ fprintf(fp, "# adb shell setprop libc.debug.malloc.options backtrace\n");
+ fprintf(fp, "# adb shell start\n");
+ fclose(fp);
+ return false;
+ }
+
+ fprintf(fp, "Android Native Heap Dump v1.0\n\n");
+
+ std::vector<const Header*> list;
+ size_t total_memory;
+ g_debug->track->GetListBySizeThenBacktrace(&list, &total_memory);
+ fprintf(fp, "Total memory: %zu\n", total_memory);
+ fprintf(fp, "Allocation records: %zd\n", list.size());
+ fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
+ fprintf(fp, "\n");
+
+ for (const auto& header : list) {
+ const BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
+ fprintf(fp, "z %d sz %8zu num 1 bt", (header->zygote_child_alloc()) ? 1 : 0,
+ header->real_size());
+ for (size_t i = 0; i < back_header->num_frames; i++) {
+ if (back_header->frames[i] == 0) {
+ break;
+ }
+#ifdef __LP64__
+ fprintf(fp, " %016" PRIxPTR, back_header->frames[i]);
+#else
+ fprintf(fp, " %08" PRIxPTR, back_header->frames[i]);
+#endif
+ }
+ fprintf(fp, "\n");
+ }
+
+ fprintf(fp, "MAPS\n");
+ std::string content;
+ if (!android::base::ReadFileToString("/proc/self/maps", &content)) {
+ fprintf(fp, "Could not open /proc/self/maps\n");
+ } else {
+ fprintf(fp, "%s", content.c_str());
+ }
+ fprintf(fp, "END\n");
+ fclose(fp);
+ return true;
+}
diff --git a/libc/malloc_debug/malloc_debug.h b/libc/malloc_debug/malloc_debug.h
index 347fae236..4a1e8dad1 100644
--- a/libc/malloc_debug/malloc_debug.h
+++ b/libc/malloc_debug/malloc_debug.h
@@ -54,7 +54,8 @@ struct Header {
size_t size;
size_t usable_size;
size_t real_size() const { return size & ~(1U << 31); }
- void set_zygote() { size |= 1U << 31; }
+ void set_zygote_child_alloc() { size |= 1U << 31; }
+ bool zygote_child_alloc() const { return size & (1U << 31); }
static size_t max_size() { return (1U << 31) - 1; }
} __attribute__((packed));
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 77dc84842..ee8fe0691 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -60,6 +60,9 @@ std::string usage_string(
"6 malloc_debug backtrace[=XX]\n"
"6 malloc_debug Enable capturing the backtrace at the point of allocation.\n"
"6 malloc_debug If XX is set it sets the number of backtrace frames.\n"
+ "6 malloc_debug This option also enables dumping the backtrace heap data\n"
+ "6 malloc_debug when a signal is received. The data is dumped to the file\n"
+ "6 malloc_debug backtrace_dump_prefix.<PID>.txt.\n"
"6 malloc_debug The default is 16 frames, the max number of frames is 256.\n"
"6 malloc_debug \n"
"6 malloc_debug backtrace_enable_on_signal[=XX]\n"
@@ -68,6 +71,18 @@ std::string usage_string(
"6 malloc_debug receives a signal. If XX is set it sets the number of backtrace\n"
"6 malloc_debug frames. The default is 16 frames, the max number of frames is 256.\n"
"6 malloc_debug \n"
+ "6 malloc_debug backtrace_dump_prefix[=FILE]\n"
+ "6 malloc_debug This option only has meaning if the backtrace option has been specified.\n"
+ "6 malloc_debug This is the prefix of the name of the file to which backtrace heap\n"
+ "6 malloc_debug data will be dumped. The file will be named backtrace_dump_prefix.<PID>.txt.\n"
+ "6 malloc_debug The default is /data/local/tmp/backtrace_heap.\n"
+ "6 malloc_debug \n"
+ "6 malloc_debug backtrace_dump_on_exit\n"
+ "6 malloc_debug This option only has meaning if the backtrace option has been specified.\n"
+ "6 malloc_debug This will cause all live allocations to be dumped to the file\n"
+ "6 malloc_debug backtrace_dump_prefix.<PID>.final.txt.\n"
+ "6 malloc_debug The default is false.\n"
+ "6 malloc_debug \n"
"6 malloc_debug fill_on_alloc[=XX]\n"
"6 malloc_debug On first allocation, fill with the value 0xeb.\n"
"6 malloc_debug If XX is set it will only fill up to XX bytes of the\n"
@@ -292,12 +307,14 @@ TEST_F(MallocDebugConfigTest, backtrace) {
ASSERT_EQ(64U, config->backtrace_frames());
ASSERT_TRUE(config->backtrace_enabled());
ASSERT_FALSE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_TRUE(InitConfig("backtrace")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
ASSERT_TRUE(config->backtrace_enabled());
ASSERT_FALSE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -309,12 +326,14 @@ TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal) {
ASSERT_EQ(64U, config->backtrace_frames());
ASSERT_FALSE(config->backtrace_enabled());
ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_TRUE(InitConfig("backtrace_enable_on_signal")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
ASSERT_FALSE(config->backtrace_enabled());
ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -326,12 +345,14 @@ TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal_init) {
ASSERT_EQ(64U, config->backtrace_frames());
ASSERT_FALSE(config->backtrace_enabled());
ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_TRUE(InitConfig("backtrace")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
ASSERT_TRUE(config->backtrace_enabled());
ASSERT_FALSE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -343,12 +364,46 @@ TEST_F(MallocDebugConfigTest, backtrace_enable_and_backtrace) {
ASSERT_EQ(16U, config->backtrace_frames());
ASSERT_TRUE(config->backtrace_enabled());
ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
ASSERT_TRUE(InitConfig("backtrace backtrace_enable_on_signal")) << getFakeLogPrint();
ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->backtrace_frames());
ASSERT_TRUE(config->backtrace_enabled());
ASSERT_TRUE(config->backtrace_enable_on_signal());
+ ASSERT_FALSE(config->backtrace_dump_on_exit());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, backtrace_dump_on_exit) {
+ ASSERT_TRUE(InitConfig("backtrace_dump_on_exit")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_TRUE(config->backtrace_dump_on_exit());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, backtrace_dump_on_exit_error) {
+ ASSERT_FALSE(InitConfig("backtrace_dump_on_exit=something")) << getFakeLogPrint();
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string log_msg(
+ "6 malloc_debug malloc_testing: value set for option 'backtrace_dump_on_exit' "
+ "which does not take a value\n");
+ ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, backtrace_dump_prefix) {
+ ASSERT_TRUE(InitConfig("backtrace_dump_prefix")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_EQ("/data/local/tmp/backtrace_heap", config->backtrace_dump_prefix());
+
+ ASSERT_TRUE(InitConfig("backtrace_dump_prefix=/fake/location")) << getFakeLogPrint();
+ ASSERT_EQ(0U, config->options());
+ ASSERT_EQ("/fake/location", config->backtrace_dump_prefix());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 4fdba2ef9..37d805751 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -32,6 +32,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <private/bionic_macros.h>
#include <private/bionic_malloc_dispatch.h>
@@ -82,6 +83,8 @@ static size_t get_tag_offset(uint32_t flags = 0, size_t backtrace_frames = 0) {
static constexpr const char RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
+static constexpr const char BACKTRACE_DUMP_PREFIX[] = "/data/local/tmp/backtrace_heap";
+
class MallocDebugTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -104,6 +107,8 @@ class MallocDebugTest : public ::testing::Test {
initialized = true;
}
+ void BacktraceDumpOnSignal(bool trigger_with_alloc);
+
bool initialized;
int zygote;
@@ -132,7 +137,7 @@ MallocDispatch MallocDebugTest::dispatch = {
mallopt,
};
-void VerifyAllocCalls() {
+void VerifyAllocCalls(bool backtrace_enabled) {
size_t alloc_size = 1024;
// Verify debug_malloc.
@@ -186,17 +191,23 @@ void VerifyAllocCalls() {
ASSERT_TRUE(pointer == nullptr);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
+ std::string expected_log;
+ if (backtrace_enabled) {
+ expected_log += android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ }
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, fill_generic) {
Init("fill");
- VerifyAllocCalls();
+ VerifyAllocCalls(false);
}
TEST_F(MallocDebugTest, fill_on_alloc_generic) {
Init("fill_on_alloc");
- VerifyAllocCalls();
+ VerifyAllocCalls(false);
}
TEST_F(MallocDebugTest, fill_on_alloc_partial) {
@@ -275,7 +286,7 @@ TEST_F(MallocDebugTest, free_track_partial) {
TEST_F(MallocDebugTest, all_options) {
Init("guard backtrace fill expand_alloc free_track leak_track");
- VerifyAllocCalls();
+ VerifyAllocCalls(true);
}
TEST_F(MallocDebugTest, expand_alloc) {
@@ -624,6 +635,9 @@ TEST_F(MallocDebugTest, leak_track_no_frees_with_backtrace) {
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ expected_log += android::base::StringPrintf(
"6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
pointer3);
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
@@ -649,7 +663,6 @@ TEST_F(MallocDebugTest, leak_track_no_frees_with_backtrace) {
expected_log += "6 malloc_debug #00 pc 0x1000\n";
expected_log += "6 malloc_debug #01 pc 0x2000\n";
expected_log += "6 malloc_debug #02 pc 0x3000\n";
-
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
@@ -1022,7 +1035,10 @@ TEST_F(MallocDebugTest, get_malloc_leak_info_empty) {
ASSERT_EQ(0U, backtrace_size);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
@@ -1065,7 +1081,10 @@ TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
debug_free(pointer);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
@@ -1144,7 +1163,10 @@ TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
debug_free(pointers[2]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, get_malloc_leak_info_multi_skip_empty_backtrace) {
@@ -1215,6 +1237,185 @@ TEST_F(MallocDebugTest, get_malloc_leak_info_multi_skip_empty_backtrace) {
debug_free(pointers[2]);
ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+static std::string SanitizeHeapData(const std::string& data) {
+ // Remove the map data since it's not consistent.
+ std::string sanitized;
+ bool skip_map_data = false;
+ bool map_data_found = false;
+ for (auto& line : android::base::Split(data, "\n")) {
+ if (skip_map_data) {
+ if (line == "END") {
+ if (map_data_found) {
+ sanitized += "MAP_DATA\n";
+ map_data_found = false;
+ }
+ skip_map_data = false;
+ } else {
+ map_data_found = true;
+ continue;
+ }
+ }
+ if (line == "MAPS") {
+ skip_map_data = true;
+ }
+ sanitized += line + '\n';
+ }
+ return sanitized;
+}
+
+void MallocDebugTest::BacktraceDumpOnSignal(bool trigger_with_alloc) {
+ Init("backtrace=4");
+
+ backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+ backtrace_fake_add(std::vector<uintptr_t> {0x300, 0x400});
+ backtrace_fake_add(std::vector<uintptr_t> {0x500, 0x600});
+
+ backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xa100, 0xb200});
+ backtrace_fake_add(std::vector<uintptr_t> {0xa300, 0xb300});
+
+ std::vector<void*> pointers;
+ zygote = 1;
+ pointers.push_back(debug_malloc(100));
+ ASSERT_TRUE(pointers.back() != nullptr);
+ pointers.push_back(debug_malloc(40));
+ ASSERT_TRUE(pointers.back() != nullptr);
+ pointers.push_back(debug_malloc(200));
+ ASSERT_TRUE(pointers.back() != nullptr);
+
+ zygote = 0;
+ pointers.push_back(debug_malloc(10));
+ ASSERT_TRUE(pointers.back() != nullptr);
+ pointers.push_back(debug_malloc(50));
+ ASSERT_TRUE(pointers.back() != nullptr);
+ pointers.push_back(debug_malloc(5));
+ ASSERT_TRUE(pointers.back() != nullptr);
+
+ // Dump all of the data accumulated so far.
+ ASSERT_TRUE(kill(getpid(), SIGRTMAX - 17) == 0);
+ sleep(1);
+
+ // This triggers the dumping.
+ if (trigger_with_alloc) {
+ pointers.push_back(debug_malloc(23));
+ ASSERT_TRUE(pointers.back() != nullptr);
+ } else {
+ debug_free(pointers.back());
+ pointers.pop_back();
+ }
+
+ for (auto* pointer : pointers) {
+ debug_free(pointer);
+ }
+
+ // Read all of the contents.
+ std::string actual;
+ std::string name = android::base::StringPrintf("%s.%d.txt", BACKTRACE_DUMP_PREFIX, getpid());
+ ASSERT_TRUE(android::base::ReadFileToString(name, &actual));
+ ASSERT_EQ(0, unlink(name.c_str()));
+
+ std::string sanitized(SanitizeHeapData(actual));
+
+ std::string expected =
+ "Android Native Heap Dump v1.0\n"
+ "\n"
+ "Total memory: 405\n"
+ "Allocation records: 6\n"
+ "Backtrace size: 4\n"
+ "\n"
+#if defined(__LP64__)
+ "z 0 sz 5 num 1 bt 000000000000a300 000000000000b300\n"
+ "z 0 sz 10 num 1 bt 000000000000a000 000000000000b000\n"
+ "z 0 sz 50 num 1 bt 000000000000a100 000000000000b200\n"
+ "z 1 sz 40 num 1 bt 0000000000000300 0000000000000400\n"
+ "z 1 sz 100 num 1 bt 0000000000000100 0000000000000200\n"
+ "z 1 sz 200 num 1 bt 0000000000000500 0000000000000600\n"
+#else
+ "z 0 sz 5 num 1 bt 0000a300 0000b300\n"
+ "z 0 sz 10 num 1 bt 0000a000 0000b000\n"
+ "z 0 sz 50 num 1 bt 0000a100 0000b200\n"
+ "z 1 sz 40 num 1 bt 00000300 00000400\n"
+ "z 1 sz 100 num 1 bt 00000100 00000200\n"
+ "z 1 sz 200 num 1 bt 00000500 00000600\n"
+#endif
+ "MAPS\n"
+ "MAP_DATA\n"
+ "END\n\n";
+ ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual;
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ expected_log += android::base::StringPrintf(
+ "6 malloc_debug Dumping to file: /data/local/tmp/backtrace_heap.%d.txt\n\n", getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_dump_on_signal_by_malloc) {
+ BacktraceDumpOnSignal(true);
+}
+
+TEST_F(MallocDebugTest, backtrace_dump_on_signal_by_free) {
+ BacktraceDumpOnSignal(false);
+}
+
+TEST_F(MallocDebugTest, backtrace_dump_on_exit) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ Init("backtrace=4 backtrace_dump_on_exit");
+ backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+ backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000, 0xc000});
+
+ std::vector<void*> pointers;
+ pointers.push_back(debug_malloc(300));
+ pointers.push_back(debug_malloc(400));
+ pointers.push_back(debug_malloc(500));
+
+ // Call the exit function manually.
+ debug_finalize();
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+ ASSERT_EQ(pid, waitpid(pid, nullptr, 0));
+
+ // Read all of the contents.
+ std::string actual;
+ std::string name = android::base::StringPrintf("%s.%d.exit.txt", BACKTRACE_DUMP_PREFIX, pid);
+ ASSERT_TRUE(android::base::ReadFileToString(name, &actual));
+ ASSERT_EQ(0, unlink(name.c_str()));
+
+ std::string sanitized(SanitizeHeapData(actual));
+
+ std::string expected =
+ "Android Native Heap Dump v1.0\n"
+ "\n"
+ "Total memory: 1200\n"
+ "Allocation records: 3\n"
+ "Backtrace size: 4\n"
+ "\n"
+#if defined(__LP64__)
+ "z 0 sz 300 num 1 bt 0000000000000100 0000000000000200\n"
+ "z 0 sz 400 num 1 bt 000000000000a000 000000000000b000\n"
+ "z 0 sz 500 num 1 bt 000000000000a000 000000000000b000 000000000000c000\n"
+#else
+ "z 0 sz 300 num 1 bt 00000100 00000200\n"
+ "z 0 sz 400 num 1 bt 0000a000 0000b000\n"
+ "z 0 sz 500 num 1 bt 0000a000 0000b000 0000c000\n"
+#endif
+ "MAPS\n"
+ "MAP_DATA\n"
+ "END\n\n";
+ ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual;
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
@@ -1317,6 +1518,9 @@ TEST_F(MallocDebugTest, backtrace_enable_on_signal) {
std::string expected_log = android::base::StringPrintf(
"4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
SIGRTMAX - 19, getpid());
+ expected_log += android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
@@ -1439,7 +1643,10 @@ TEST_F(MallocDebugTest, zygote_set) {
debug_free(pointer);
ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugTest, max_size) {
@@ -1596,6 +1803,7 @@ void VerifyRecordAllocs() {
// Read all of the contents.
std::string actual;
ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
+ ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
ASSERT_STREQ(expected.c_str(), actual.c_str());
@@ -1653,6 +1861,7 @@ TEST_F(MallocDebugTest, record_allocs_max) {
// Read all of the contents.
std::string actual;
ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
+ ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
ASSERT_STREQ(expected.c_str(), actual.c_str());
@@ -1694,6 +1903,7 @@ TEST_F(MallocDebugTest, record_allocs_thread_done) {
// Read all of the contents.
std::string actual;
ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
+ ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
ASSERT_STREQ(expected.c_str(), actual.c_str());
@@ -1748,6 +1958,7 @@ TEST_F(MallocDebugTest, record_allocs_file_name_fail) {
expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
+ ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
ASSERT_STREQ(expected.c_str(), actual.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());