Remove dead non-proto tombstone reporting code.
Bug: 197981919 Change-Id: I58a98070198ef0b686229bd54f87b9073df12d66
This commit is contained in:
parent
0326984c42
commit
a6fac881b2
6 changed files with 0 additions and 423 deletions
|
@ -282,7 +282,6 @@ cc_test {
|
|||
"libdebuggerd/test/elf_fake.cpp",
|
||||
"libdebuggerd/test/log_fake.cpp",
|
||||
"libdebuggerd/test/open_files_list_test.cpp",
|
||||
"libdebuggerd/test/tombstone_test.cpp",
|
||||
"libdebuggerd/test/utility_test.cpp",
|
||||
],
|
||||
|
||||
|
|
|
@ -161,112 +161,3 @@ void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinde
|
|||
|
||||
set_human_readable_cause(cause, crash_address_);
|
||||
}
|
||||
|
||||
void GwpAsanCrashData::DumpCause(log_t* log) const {
|
||||
if (!CrashIsMine()) {
|
||||
ALOGE("Internal Error: DumpCause() on a non-GWP-ASan crash.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (error_ == gwp_asan::Error::UNKNOWN) {
|
||||
_LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: Unknown error occurred at 0x%" PRIxPTR ".\n",
|
||||
crash_address_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!responsible_allocation_) {
|
||||
_LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: %s at 0x%" PRIxPTR ".\n", error_string_,
|
||||
crash_address_);
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t alloc_address = __gwp_asan_get_allocation_address(responsible_allocation_);
|
||||
size_t alloc_size = __gwp_asan_get_allocation_size(responsible_allocation_);
|
||||
|
||||
uintptr_t diff;
|
||||
const char* location_str;
|
||||
|
||||
if (crash_address_ < alloc_address) {
|
||||
// Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "left of";
|
||||
diff = alloc_address - crash_address_;
|
||||
} else if (crash_address_ - alloc_address < alloc_size) {
|
||||
// Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "into";
|
||||
diff = crash_address_ - alloc_address;
|
||||
} else {
|
||||
// Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef, or
|
||||
// Invalid Free, 47 bytes right of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "right of";
|
||||
diff = crash_address_ - alloc_address;
|
||||
if (error_ == gwp_asan::Error::BUFFER_OVERFLOW) {
|
||||
diff -= alloc_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
|
||||
const char* byte_suffix = "s";
|
||||
if (diff == 1) {
|
||||
byte_suffix = "";
|
||||
}
|
||||
_LOG(log, logtype::HEADER,
|
||||
"Cause: [GWP-ASan]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
|
||||
error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
|
||||
}
|
||||
|
||||
bool GwpAsanCrashData::HasDeallocationTrace() const {
|
||||
assert(CrashIsMine() && "HasDeallocationTrace(): Crash is not mine!");
|
||||
if (!responsible_allocation_ || !__gwp_asan_is_deallocated(responsible_allocation_)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GwpAsanCrashData::DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
|
||||
assert(HasDeallocationTrace() && "DumpDeallocationTrace(): No dealloc trace!");
|
||||
uint64_t thread_id = __gwp_asan_get_deallocation_thread_id(responsible_allocation_);
|
||||
|
||||
std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
|
||||
size_t num_frames =
|
||||
__gwp_asan_get_deallocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
|
||||
|
||||
if (thread_id == gwp_asan::kInvalidThreadID) {
|
||||
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread <unknown>:\n");
|
||||
} else {
|
||||
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %" PRIu64 ":\n", thread_id);
|
||||
}
|
||||
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < num_frames; ++i) {
|
||||
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool GwpAsanCrashData::HasAllocationTrace() const {
|
||||
assert(CrashIsMine() && "HasAllocationTrace(): Crash is not mine!");
|
||||
return responsible_allocation_ != nullptr;
|
||||
}
|
||||
|
||||
void GwpAsanCrashData::DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
|
||||
assert(HasAllocationTrace() && "DumpAllocationTrace(): No dealloc trace!");
|
||||
uint64_t thread_id = __gwp_asan_get_allocation_thread_id(responsible_allocation_);
|
||||
|
||||
std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
|
||||
size_t num_frames =
|
||||
__gwp_asan_get_allocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
|
||||
|
||||
if (thread_id == gwp_asan::kInvalidThreadID) {
|
||||
_LOG(log, logtype::BACKTRACE, "\nallocated by thread <unknown>:\n");
|
||||
} else {
|
||||
_LOG(log, logtype::BACKTRACE, "\nallocated by thread %" PRIu64 ":\n", thread_id);
|
||||
}
|
||||
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < num_frames; ++i) {
|
||||
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,26 +52,6 @@ class GwpAsanCrashData {
|
|||
// allocator crash state.
|
||||
uintptr_t GetFaultAddress() const;
|
||||
|
||||
// Dump the GWP-ASan stringified cause of this crash. May only be called if
|
||||
// CrashIsMine() returns true.
|
||||
void DumpCause(log_t* log) const;
|
||||
|
||||
// Returns whether this crash has a deallocation trace. May only be called if
|
||||
// CrashIsMine() returns true.
|
||||
bool HasDeallocationTrace() const;
|
||||
|
||||
// Dump the GWP-ASan deallocation trace for this crash. May only be called if
|
||||
// HasDeallocationTrace() returns true.
|
||||
void DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
// Returns whether this crash has a allocation trace. May only be called if
|
||||
// CrashIsMine() returns true.
|
||||
bool HasAllocationTrace() const;
|
||||
|
||||
// Dump the GWP-ASan allocation trace for this crash. May only be called if
|
||||
// HasAllocationTrace() returns true.
|
||||
void DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -34,16 +34,12 @@ class ScudoCrashData {
|
|||
|
||||
bool CrashIsMine() const;
|
||||
|
||||
void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
|
||||
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
private:
|
||||
scudo_error_info error_info_ = {};
|
||||
uintptr_t untagged_fault_addr_;
|
||||
|
||||
void DumpReport(const scudo_error_report* report, log_t* log,
|
||||
unwindstack::Unwinder* unwinder) const;
|
||||
|
||||
void FillInCause(Cause* cause, const scudo_error_report* report,
|
||||
unwindstack::Unwinder* unwinder) const;
|
||||
};
|
||||
|
|
|
@ -130,87 +130,3 @@ void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder*
|
|||
FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder);
|
||||
}
|
||||
}
|
||||
|
||||
void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
|
||||
if (error_info_.reports[1].error_type != UNKNOWN) {
|
||||
_LOG(log, logtype::HEADER,
|
||||
"\nNote: multiple potential causes for this crash were detected, listing them in "
|
||||
"decreasing order of likelihood.\n");
|
||||
}
|
||||
|
||||
size_t report_num = 0;
|
||||
while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
|
||||
error_info_.reports[report_num].error_type != UNKNOWN) {
|
||||
DumpReport(&error_info_.reports[report_num++], log, unwinder);
|
||||
}
|
||||
}
|
||||
|
||||
void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
|
||||
unwindstack::Unwinder* unwinder) const {
|
||||
const char *error_type_str;
|
||||
switch (report->error_type) {
|
||||
case USE_AFTER_FREE:
|
||||
error_type_str = "Use After Free";
|
||||
break;
|
||||
case BUFFER_OVERFLOW:
|
||||
error_type_str = "Buffer Overflow";
|
||||
break;
|
||||
case BUFFER_UNDERFLOW:
|
||||
error_type_str = "Buffer Underflow";
|
||||
break;
|
||||
default:
|
||||
error_type_str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
uintptr_t diff;
|
||||
const char* location_str;
|
||||
|
||||
if (untagged_fault_addr_ < report->allocation_address) {
|
||||
// Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "left of";
|
||||
diff = report->allocation_address - untagged_fault_addr_;
|
||||
} else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
|
||||
// Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "into";
|
||||
diff = untagged_fault_addr_ - report->allocation_address;
|
||||
} else {
|
||||
// Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
|
||||
location_str = "right of";
|
||||
diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
|
||||
}
|
||||
|
||||
// Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
|
||||
const char* byte_suffix = "s";
|
||||
if (diff == 1) {
|
||||
byte_suffix = "";
|
||||
}
|
||||
_LOG(log, logtype::HEADER,
|
||||
"\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
|
||||
error_type_str, diff, byte_suffix, location_str, report->allocation_size,
|
||||
report->allocation_address);
|
||||
|
||||
if (report->allocation_trace[0]) {
|
||||
_LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i];
|
||||
++i) {
|
||||
unwindstack::FrameData frame_data =
|
||||
unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (report->deallocation_trace[0]) {
|
||||
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < arraysize(report->deallocation_trace) && report->deallocation_trace[i];
|
||||
++i) {
|
||||
unwindstack::FrameData frame_data =
|
||||
unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
|
||||
frame_data.num = i;
|
||||
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "libdebuggerd/utility.h"
|
||||
|
||||
#include "UnwinderMock.h"
|
||||
#include "host_signal_fixup.h"
|
||||
#include "log_fake.h"
|
||||
|
||||
#include "gwp_asan.cpp"
|
||||
|
||||
using ::testing::MatchesRegex;
|
||||
|
||||
class TombstoneTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
unwinder_mock_.reset(new UnwinderMock());
|
||||
|
||||
char tmp_file[256];
|
||||
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
|
||||
memcpy(tmp_file, data_template, sizeof(data_template));
|
||||
int tombstone_fd = mkstemp(tmp_file);
|
||||
if (tombstone_fd == -1) {
|
||||
const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
|
||||
memcpy(tmp_file, tmp_template, sizeof(tmp_template));
|
||||
tombstone_fd = mkstemp(tmp_file);
|
||||
if (tombstone_fd == -1) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (unlink(tmp_file) == -1) {
|
||||
abort();
|
||||
}
|
||||
|
||||
log_.tfd = tombstone_fd;
|
||||
amfd_data_.clear();
|
||||
log_.amfd_data = &amfd_data_;
|
||||
log_.crashed_tid = 12;
|
||||
log_.current_tid = 12;
|
||||
log_.should_retrieve_logcat = false;
|
||||
|
||||
resetLogs();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (log_.tfd >= 0) {
|
||||
close(log_.tfd);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<UnwinderMock> unwinder_mock_;
|
||||
|
||||
log_t log_;
|
||||
std::string amfd_data_;
|
||||
};
|
||||
|
||||
class GwpAsanCrashDataTest : public GwpAsanCrashData {
|
||||
public:
|
||||
GwpAsanCrashDataTest(
|
||||
gwp_asan::Error error,
|
||||
const gwp_asan::AllocationMetadata *responsible_allocation) :
|
||||
GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
|
||||
is_gwp_asan_responsible_ = true;
|
||||
error_ = error;
|
||||
responsible_allocation_ = responsible_allocation;
|
||||
error_string_ = gwp_asan::ErrorToString(error_);
|
||||
}
|
||||
|
||||
void SetCrashAddress(uintptr_t crash_address) {
|
||||
crash_address_ = crash_address;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
|
||||
crash_data.SetCrashAddress(0x1000);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free, 0 bytes "
|
||||
"into a 32-byte allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
|
||||
crash_data.SetCrashAddress(0x1000);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free, 0 bytes into a "
|
||||
"32-byte allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
|
||||
crash_data.SetCrashAddress(0x1025);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(
|
||||
tombstone_contents,
|
||||
MatchesRegex(
|
||||
"Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
|
||||
"allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
|
||||
crash_data.SetCrashAddress(0xffe);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(
|
||||
tombstone_contents,
|
||||
MatchesRegex(
|
||||
"Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
|
||||
"allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
|
||||
crash_data.SetCrashAddress(0x1001);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(
|
||||
tombstone_contents,
|
||||
MatchesRegex(
|
||||
"Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
|
||||
"allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
||||
|
||||
TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
|
||||
gwp_asan::AllocationMetadata meta;
|
||||
meta.Addr = 0x1000;
|
||||
meta.RequestedSize = 32;
|
||||
|
||||
GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
|
||||
crash_data.SetCrashAddress(0x1021);
|
||||
|
||||
crash_data.DumpCause(&log_);
|
||||
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
|
||||
std::string tombstone_contents;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
|
||||
ASSERT_THAT(
|
||||
tombstone_contents,
|
||||
MatchesRegex(
|
||||
"Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
|
||||
"allocation at 0x[a-fA-F0-9]+\n"));
|
||||
}
|
Loading…
Reference in a new issue