Merge "Add options to only backtrace specific sizes."
This commit is contained in:
commit
08f98b6734
8 changed files with 342 additions and 9 deletions
|
@ -82,6 +82,19 @@ const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
|
|||
{REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
|
||||
},
|
||||
|
||||
{
|
||||
"backtrace_size",
|
||||
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
|
||||
},
|
||||
{
|
||||
"backtrace_min_size",
|
||||
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
|
||||
},
|
||||
{
|
||||
"backtrace_max_size",
|
||||
{BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
|
||||
},
|
||||
|
||||
{
|
||||
"backtrace",
|
||||
{BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
|
||||
|
@ -297,6 +310,23 @@ bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Config::SetBacktraceSize(const std::string& option, const std::string& value) {
|
||||
if (!ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_)) {
|
||||
return false;
|
||||
}
|
||||
backtrace_max_size_bytes_ = backtrace_min_size_bytes_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Config::SetBacktraceMinSize(const std::string& option, const std::string& value) {
|
||||
return ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_);
|
||||
}
|
||||
|
||||
bool Config::SetBacktraceMaxSize(const std::string& option, const std::string& value) {
|
||||
return ParseValue(option, value, 1, SIZE_MAX, &backtrace_max_size_bytes_);
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
@ -403,6 +433,8 @@ bool Config::Init(const char* options_str) {
|
|||
backtrace_enabled_ = false;
|
||||
backtrace_dump_on_exit_ = false;
|
||||
backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
|
||||
backtrace_min_size_bytes_ = 0;
|
||||
backtrace_max_size_bytes_ = SIZE_MAX;
|
||||
check_unreachable_signal_ = SIGRTMAX - 16;
|
||||
|
||||
// Process each option name we can find.
|
||||
|
|
|
@ -47,6 +47,7 @@ constexpr uint64_t BACKTRACE_FULL = 0x400;
|
|||
constexpr uint64_t ABORT_ON_ERROR = 0x800;
|
||||
constexpr uint64_t VERBOSE = 0x1000;
|
||||
constexpr uint64_t CHECK_UNREACHABLE_ON_SIGNAL = 0x2000;
|
||||
constexpr uint64_t BACKTRACE_SPECIFIC_SIZES = 0x4000;
|
||||
|
||||
// In order to guarantee posix compliance, set the minimum alignment
|
||||
// to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
|
||||
|
@ -90,6 +91,9 @@ class Config {
|
|||
uint8_t fill_alloc_value() const { return fill_alloc_value_; }
|
||||
uint8_t fill_free_value() const { return fill_free_value_; }
|
||||
|
||||
size_t backtrace_min_size_bytes() const { return backtrace_min_size_bytes_; }
|
||||
size_t backtrace_max_size_bytes() const { return backtrace_max_size_bytes_; }
|
||||
|
||||
int record_allocs_signal() const { return record_allocs_signal_; }
|
||||
size_t record_allocs_num_entries() const { return record_allocs_num_entries_; }
|
||||
const std::string& record_allocs_file() const { return record_allocs_file_; }
|
||||
|
@ -121,6 +125,10 @@ class Config {
|
|||
bool SetBacktraceDumpOnExit(const std::string& option, const std::string& value);
|
||||
bool SetBacktraceDumpPrefix(const std::string& option, const std::string& value);
|
||||
|
||||
bool SetBacktraceSize(const std::string& option, const std::string& value);
|
||||
bool SetBacktraceMinSize(const std::string& option, const std::string& value);
|
||||
bool SetBacktraceMaxSize(const std::string& option, const std::string& value);
|
||||
|
||||
bool SetExpandAlloc(const std::string& option, const std::string& value);
|
||||
|
||||
bool SetFreeTrack(const std::string& option, const std::string& value);
|
||||
|
@ -145,6 +153,8 @@ class Config {
|
|||
size_t backtrace_frames_ = 0;
|
||||
bool backtrace_dump_on_exit_ = false;
|
||||
std::string backtrace_dump_prefix_;
|
||||
size_t backtrace_min_size_bytes_ = 0;
|
||||
size_t backtrace_max_size_bytes_ = 0;
|
||||
|
||||
size_t fill_on_alloc_bytes_ = 0;
|
||||
size_t fill_on_free_bytes_ = 0;
|
||||
|
|
|
@ -136,7 +136,22 @@ bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t PointerData::AddBacktrace(size_t num_frames) {
|
||||
static inline bool ShouldBacktraceAllocSize(size_t size_bytes) {
|
||||
static bool only_backtrace_specific_sizes =
|
||||
g_debug->config().options() & BACKTRACE_SPECIFIC_SIZES;
|
||||
if (!only_backtrace_specific_sizes) {
|
||||
return true;
|
||||
}
|
||||
static size_t min_size_bytes = g_debug->config().backtrace_min_size_bytes();
|
||||
static size_t max_size_bytes = g_debug->config().backtrace_max_size_bytes();
|
||||
return size_bytes >= min_size_bytes && size_bytes <= max_size_bytes;
|
||||
}
|
||||
|
||||
size_t PointerData::AddBacktrace(size_t num_frames, size_t size_bytes) {
|
||||
if (!ShouldBacktraceAllocSize(size_bytes)) {
|
||||
return kBacktraceEmptyIndex;
|
||||
}
|
||||
|
||||
std::vector<uintptr_t> frames;
|
||||
std::vector<unwindstack::FrameData> frames_info;
|
||||
if (g_debug->config().options() & BACKTRACE_FULL) {
|
||||
|
@ -198,7 +213,7 @@ void PointerData::RemoveBacktrace(size_t hash_index) {
|
|||
void PointerData::Add(const void* ptr, size_t pointer_size) {
|
||||
size_t hash_index = 0;
|
||||
if (backtrace_enabled_) {
|
||||
hash_index = AddBacktrace(g_debug->config().backtrace_frames());
|
||||
hash_index = AddBacktrace(g_debug->config().backtrace_frames(), pointer_size);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
|
@ -336,11 +351,11 @@ void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
|||
}
|
||||
}
|
||||
|
||||
void* PointerData::AddFreed(const void* ptr) {
|
||||
void* PointerData::AddFreed(const void* ptr, size_t size_bytes) {
|
||||
size_t hash_index = 0;
|
||||
size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
|
||||
if (num_frames) {
|
||||
hash_index = AddBacktrace(num_frames);
|
||||
hash_index = AddBacktrace(num_frames, size_bytes);
|
||||
}
|
||||
|
||||
void* last = nullptr;
|
||||
|
|
|
@ -137,13 +137,13 @@ class PointerData : public OptionData {
|
|||
|
||||
static void IteratePointers(std::function<void(uintptr_t pointer)> fn);
|
||||
|
||||
static size_t AddBacktrace(size_t num_frames);
|
||||
static size_t AddBacktrace(size_t num_frames, size_t size_bytes);
|
||||
static void RemoveBacktrace(size_t hash_index);
|
||||
|
||||
static void Add(const void* pointer, size_t size);
|
||||
static void Remove(const void* pointer);
|
||||
|
||||
static void* AddFreed(const void* pointer);
|
||||
static void* AddFreed(const void* pointer, size_t size_bytes);
|
||||
static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
|
||||
static void LogFreeBacktrace(const void* ptr);
|
||||
static void VerifyFreedPointer(const FreePointerInfoType& info);
|
||||
|
|
|
@ -160,6 +160,41 @@ 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.
|
||||
|
||||
### backtrace\_min\_size=ALLOCATION\_SIZE\_BYTES
|
||||
As of U, setting this in combination with the backtrace option means
|
||||
that only allocations of a size greater than or equal to
|
||||
**ALLOCATION\_SIZE\_BYTES** will be backtraced. When used in combination
|
||||
with the backtrace\_max\_size option, then allocations greater than or
|
||||
equal to backtrace\_min\_size and less than or equal to
|
||||
backtrace\_max\_size will be backtraced. The backtrace\_size option
|
||||
overrides this option, and should not be used at the same time.
|
||||
|
||||
This option can also be used in combination with other tools such
|
||||
as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
|
||||
to only get backtraces for sizes of allocations listed as being leaked.
|
||||
|
||||
### backtrace\_max\_size=ALLOCATION\_SIZE\_BYTES
|
||||
As of U, setting this in combination with the backtrace option means
|
||||
that only allocations of a size less than or equal to
|
||||
**ALLOCATION\_SIZE\_BYTES** will be backtraced. When used in combination
|
||||
with the backtrace\_min\_size option, then allocations greater than or
|
||||
equal to backtrace\_min\_size and less than or equal to
|
||||
backtrace\_max\_size will be backtraced. The backtrace\_size option
|
||||
overrides this option, and should not be used at the same time.
|
||||
|
||||
This option can also be used in combination with other tools such
|
||||
as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
|
||||
to only get backtraces for sizes of allocations listed as being leaked.
|
||||
|
||||
### backtrace\_size=ALLOCATION\_SIZE\_BYTES
|
||||
As of U, setting this in combination with the backtrace option means
|
||||
that only allocations of size **ALLOCATION\_SIZE\_BYTES** will be backtraced.
|
||||
This option overrides the backtrace\_min\_size and the backtrace\_max\_size.
|
||||
|
||||
This option can also be used in combination with other tools such
|
||||
as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
|
||||
to only get backtraces for sizes of allocations listed as being leaked.
|
||||
|
||||
### backtrace\_full
|
||||
As of Q, any time that a backtrace is gathered, a different algorithm is used
|
||||
that is extra thorough and can unwind through Java frames. This will run
|
||||
|
|
|
@ -522,8 +522,8 @@ static void InternalFree(void* pointer) {
|
|||
|
||||
if (g_debug->config().options() & FILL_ON_FREE) {
|
||||
size_t fill_bytes = g_debug->config().fill_on_free_bytes();
|
||||
bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
|
||||
memset(pointer, g_debug->config().fill_free_value(), bytes);
|
||||
fill_bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
|
||||
memset(pointer, g_debug->config().fill_free_value(), fill_bytes);
|
||||
}
|
||||
|
||||
if (g_debug->TrackPointers()) {
|
||||
|
@ -536,7 +536,7 @@ static void InternalFree(void* pointer) {
|
|||
// frees at the same time and we wind up trying to really free this
|
||||
// pointer from another thread, while still trying to free it in
|
||||
// this function.
|
||||
pointer = PointerData::AddFreed(pointer);
|
||||
pointer = PointerData::AddFreed(pointer, bytes);
|
||||
if (pointer != nullptr) {
|
||||
if (g_debug->HeaderEnabled()) {
|
||||
pointer = g_debug->GetHeader(pointer)->orig_pointer;
|
||||
|
|
|
@ -779,3 +779,69 @@ TEST_F(MallocDebugConfigTest, trigger_check_unreachable_on_signal_fail) {
|
|||
"which does not take a value\n");
|
||||
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugConfigTest, size) {
|
||||
ASSERT_TRUE(InitConfig("backtrace_size=37")) << getFakeLogPrint();
|
||||
ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
|
||||
ASSERT_EQ(37U, config->backtrace_min_size_bytes());
|
||||
ASSERT_EQ(37U, config->backtrace_max_size_bytes());
|
||||
|
||||
ASSERT_FALSE(InitConfig("backtrace_size")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_size=0")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_size=-1")) << getFakeLogPrint();
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_size'\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_size', value "
|
||||
"must be >= 1: 0\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_size', value "
|
||||
"cannot be negative: -1\n" +
|
||||
usage_string);
|
||||
ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugConfigTest, min_size) {
|
||||
ASSERT_TRUE(InitConfig("backtrace_min_size=9")) << getFakeLogPrint();
|
||||
ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
|
||||
ASSERT_EQ(9U, config->backtrace_min_size_bytes());
|
||||
ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
|
||||
|
||||
ASSERT_FALSE(InitConfig("backtrace_min_size")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_min_size=0")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_min_size=-1")) << getFakeLogPrint();
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size'\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size', "
|
||||
"value must be >= 1: 0\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size', "
|
||||
"value cannot be negative: -1\n" +
|
||||
usage_string);
|
||||
ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugConfigTest, max_size) {
|
||||
ASSERT_TRUE(InitConfig("backtrace_max_size=13")) << getFakeLogPrint();
|
||||
ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
|
||||
ASSERT_EQ(0U, config->backtrace_min_size_bytes());
|
||||
ASSERT_EQ(13U, config->backtrace_max_size_bytes());
|
||||
|
||||
ASSERT_FALSE(InitConfig("backtrace_max_size")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_max_size=0")) << getFakeLogPrint();
|
||||
ASSERT_FALSE(InitConfig("backtrace_max_size=-1")) << getFakeLogPrint();
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size'\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size', "
|
||||
"value must be >= 1: 0\n" +
|
||||
usage_string +
|
||||
"6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size', "
|
||||
"value cannot be negative: -1\n" +
|
||||
usage_string);
|
||||
ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
|
|
@ -2754,3 +2754,178 @@ TEST_F(MallocDebugTest, check_unreachable_on_signal) {
|
|||
"6 malloc_debug Unreachable check failed, run setenforce 0 and try again.\n",
|
||||
getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_size) {
|
||||
Init("leak_track backtrace backtrace_size=120");
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
|
||||
|
||||
void* pointer1 = debug_malloc(119);
|
||||
ASSERT_TRUE(pointer1 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
|
||||
|
||||
void* pointer2 = debug_malloc(120);
|
||||
ASSERT_TRUE(pointer2 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
|
||||
|
||||
void* pointer3 = debug_malloc(121);
|
||||
ASSERT_TRUE(pointer3 != nullptr);
|
||||
|
||||
debug_finalize();
|
||||
initialized = false;
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string expected_log = android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 121 at %p (leak 1 of 3)\n", pointer3);
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 120 at %p (leak 2 of 3)\n", pointer2);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
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";
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 119 at %p (leak 3 of 3)\n", pointer1);
|
||||
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_min_size) {
|
||||
Init("leak_track backtrace backtrace_min_size=1000");
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
|
||||
|
||||
void* pointer1 = debug_malloc(500);
|
||||
ASSERT_TRUE(pointer1 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
|
||||
|
||||
void* pointer2 = debug_malloc(1000);
|
||||
ASSERT_TRUE(pointer2 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
|
||||
|
||||
void* pointer3 = debug_malloc(1001);
|
||||
ASSERT_TRUE(pointer3 != nullptr);
|
||||
|
||||
debug_finalize();
|
||||
initialized = false;
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string expected_log = android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1001 at %p (leak 1 of 3)\n",
|
||||
pointer3);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
expected_log += "6 malloc_debug #00 pc 0xa000\n";
|
||||
expected_log += "6 malloc_debug #01 pc 0xb000\n";
|
||||
expected_log += "6 malloc_debug #02 pc 0xc000\n";
|
||||
expected_log += "6 malloc_debug #03 pc 0xd000\n";
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1000 at %p (leak 2 of 3)\n",
|
||||
pointer2);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
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";
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 500 at %p (leak 3 of 3)\n", pointer1);
|
||||
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_max_size) {
|
||||
Init("leak_track backtrace backtrace_max_size=1000");
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
|
||||
|
||||
void* pointer1 = debug_malloc(1000);
|
||||
ASSERT_TRUE(pointer1 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
|
||||
|
||||
void* pointer2 = debug_malloc(1001);
|
||||
ASSERT_TRUE(pointer2 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
|
||||
|
||||
void* pointer3 = debug_malloc(5000);
|
||||
ASSERT_TRUE(pointer3 != nullptr);
|
||||
|
||||
debug_finalize();
|
||||
initialized = false;
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string expected_log = android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 5000 at %p (leak 1 of 3)\n",
|
||||
pointer3);
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1001 at %p (leak 2 of 3)\n",
|
||||
pointer2);
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1000 at %p (leak 3 of 3)\n",
|
||||
pointer1);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
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());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_min_max_size) {
|
||||
Init("leak_track backtrace backtrace_min_size=50 backtrace_max_size=1000");
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
|
||||
|
||||
void* pointer1 = debug_malloc(49);
|
||||
ASSERT_TRUE(pointer1 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
|
||||
|
||||
void* pointer2 = debug_malloc(50);
|
||||
ASSERT_TRUE(pointer2 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
|
||||
|
||||
void* pointer3 = debug_malloc(1000);
|
||||
ASSERT_TRUE(pointer3 != nullptr);
|
||||
|
||||
backtrace_fake_add(std::vector<uintptr_t>{0x1a000, 0x1b000, 0x1c000, 0x1d000, 0x1e000});
|
||||
|
||||
void* pointer4 = debug_malloc(1001);
|
||||
ASSERT_TRUE(pointer4 != nullptr);
|
||||
|
||||
debug_finalize();
|
||||
initialized = false;
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string expected_log = android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1001 at %p (leak 1 of 4)\n",
|
||||
pointer4);
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 1000 at %p (leak 2 of 4)\n",
|
||||
pointer3);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
expected_log += "6 malloc_debug #00 pc 0xa000\n";
|
||||
expected_log += "6 malloc_debug #01 pc 0xb000\n";
|
||||
expected_log += "6 malloc_debug #02 pc 0xc000\n";
|
||||
expected_log += "6 malloc_debug #03 pc 0xd000\n";
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 50 at %p (leak 3 of 4)\n", pointer2);
|
||||
expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
|
||||
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";
|
||||
|
||||
expected_log += android::base::StringPrintf(
|
||||
"6 malloc_debug +++ malloc_testing leaked block of size 49 at %p (leak 4 of 4)\n", pointer1);
|
||||
|
||||
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue