Merge "Bionic malloc debug: add a new option "abort_on_error""

This commit is contained in:
Christopher Ferris 2019-01-23 01:43:47 +00:00 committed by Gerrit Code Review
commit 0a692a6d8d
8 changed files with 98 additions and 1 deletions

View file

@ -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,

View file

@ -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.

View file

@ -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)

View file

@ -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.

View file

@ -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.

View file

@ -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) {

View file

@ -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());
}

View file

@ -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;
}