Merge "Bionic malloc debug: add a new option "abort_on_error""
This commit is contained in:
commit
0a692a6d8d
8 changed files with 98 additions and 1 deletions
|
@ -132,6 +132,9 @@ const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
|
|||
{
|
||||
"verify_pointers", {TRACK_ALLOCS, &Config::VerifyValueEmpty},
|
||||
},
|
||||
{
|
||||
"abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
|
||||
},
|
||||
};
|
||||
|
||||
bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
|
||||
|
|
|
@ -44,6 +44,7 @@ constexpr uint64_t TRACK_ALLOCS = 0x80;
|
|||
constexpr uint64_t LEAK_TRACK = 0x100;
|
||||
constexpr uint64_t RECORD_ALLOCS = 0x200;
|
||||
constexpr uint64_t BACKTRACE_FULL = 0x400;
|
||||
constexpr uint64_t ABORT_ON_ERROR = 0x800;
|
||||
|
||||
// In order to guarantee posix compliance, set the minimum alignment
|
||||
// to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
|
||||
|
|
|
@ -64,6 +64,9 @@ void GuardData::LogFailure(const Header* header, const void* pointer, const void
|
|||
error_log("Backtrace at time of failure:");
|
||||
BacktraceAndLog();
|
||||
error_log(LOG_DIVIDER);
|
||||
if (g_debug->config().options() & ABORT_ON_ERROR) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
FrontGuardData::FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset)
|
||||
|
|
|
@ -206,7 +206,7 @@ void PointerData::Remove(const void* ptr) {
|
|||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
auto entry = pointers_.find(pointer);
|
||||
if (entry == pointers_.end()) {
|
||||
// Error.
|
||||
// Attempt to remove unknown pointer.
|
||||
error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
|
||||
return;
|
||||
}
|
||||
|
@ -283,6 +283,9 @@ void PointerData::LogFreeError(const FreePointerInfoType& info, size_t usable_si
|
|||
}
|
||||
|
||||
error_log(LOG_DIVIDER);
|
||||
if (g_debug->config().options() & ABORT_ON_ERROR) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
||||
|
@ -295,6 +298,9 @@ void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
|||
error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
|
||||
info.pointer, header->tag);
|
||||
error_log(LOG_DIVIDER);
|
||||
if (g_debug->config().options() & ABORT_ON_ERROR) {
|
||||
abort();
|
||||
}
|
||||
|
||||
// Stop processing here, it is impossible to tell how the header
|
||||
// may have been damaged.
|
||||
|
|
|
@ -394,6 +394,13 @@ malloc\_usable\_size, realloc.
|
|||
|
||||
**NOTE**: This option is not available until the P release of Android.
|
||||
|
||||
### abort\_on\_error
|
||||
When malloc debug detects an error, abort after sending the error
|
||||
log message.
|
||||
|
||||
**NOTE**: If leak\_track is enabled, no abort occurs if leaks have been
|
||||
detected when the process is exiting.
|
||||
|
||||
Additional Errors
|
||||
-----------------
|
||||
There are a few other error messages that might appear in the log.
|
||||
|
|
|
@ -154,6 +154,9 @@ static void LogError(const void* pointer, const char* error_str) {
|
|||
error_log("Backtrace at time of failure:");
|
||||
BacktraceAndLog();
|
||||
error_log(LOG_DIVIDER);
|
||||
if (g_debug->config().options() & ABORT_ON_ERROR) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static bool VerifyPointer(const void* pointer, const char* function_name) {
|
||||
|
|
|
@ -725,3 +725,21 @@ TEST_F(MallocDebugConfigTest, record_allocs_max_error) {
|
|||
"value must be <= 50000000: 100000000\n");
|
||||
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugConfigTest, abort_on_error) {
|
||||
ASSERT_TRUE(InitConfig("abort_on_error")) << getFakeLogPrint();
|
||||
ASSERT_EQ(ABORT_ON_ERROR, config->options());
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugConfigTest, trigger_abort_fail) {
|
||||
ASSERT_FALSE(InitConfig("abort_on_error=200")) << getFakeLogPrint();
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
std::string log_msg(
|
||||
"6 malloc_debug malloc_testing: value set for option 'abort_on_error' "
|
||||
"which does not take a value\n");
|
||||
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
|
|
@ -2380,3 +2380,59 @@ TEST_F(MallocDebugTest, verify_pointers) {
|
|||
expected_log += DIVIDER;
|
||||
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, abort_on_error_log_error) {
|
||||
Init("abort_on_error verify_pointers");
|
||||
|
||||
void* pointer = debug_malloc(10);
|
||||
memset(pointer, 0, 10);
|
||||
debug_free(pointer);
|
||||
|
||||
ASSERT_STREQ("", getFakeLogBuf().c_str());
|
||||
ASSERT_STREQ("", getFakeLogPrint().c_str());
|
||||
|
||||
EXPECT_DEATH(debug_free(pointer), "");
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, abort_on_error_guard_corrupted) {
|
||||
Init("abort_on_error front_guard=32");
|
||||
|
||||
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
|
||||
ASSERT_TRUE(pointer != nullptr);
|
||||
pointer[-16] = 0x00;
|
||||
EXPECT_DEATH(debug_free(pointer), "");
|
||||
pointer[-16] = 0xaa;
|
||||
debug_free(pointer);
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, abort_on_error_use_after_free) {
|
||||
Init("abort_on_error free_track=100 free_track_backtrace_num_frames=0");
|
||||
|
||||
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
|
||||
ASSERT_TRUE(pointer != nullptr);
|
||||
memset(pointer, 0, 100);
|
||||
debug_free(pointer);
|
||||
|
||||
pointer[56] = 0x91;
|
||||
|
||||
EXPECT_DEATH(debug_finalize(), "");
|
||||
|
||||
pointer[56] = 0xef;
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, abort_on_error_header_tag_corrupted) {
|
||||
Init("abort_on_error free_track=100 free_track_backtrace_num_frames=0 rear_guard");
|
||||
|
||||
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
|
||||
ASSERT_TRUE(pointer != nullptr);
|
||||
memset(pointer, 0, 100);
|
||||
debug_free(pointer);
|
||||
|
||||
uint8_t tag_value = pointer[-get_tag_offset()];
|
||||
pointer[-get_tag_offset()] = 0x00;
|
||||
|
||||
EXPECT_DEATH(debug_finalize(), "");
|
||||
|
||||
pointer[-get_tag_offset()] = tag_value;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue