Merge "Add cause message when stack overflow is detected."
This commit is contained in:
commit
bcc00c5c8f
2 changed files with 67 additions and 3 deletions
|
@ -1099,3 +1099,30 @@ TEST(tombstoned, interceptless_backtrace) {
|
|||
// This should be good enough, though...
|
||||
ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
|
||||
}
|
||||
|
||||
static __attribute__((__noinline__)) void overflow_stack(void* p) {
|
||||
void* buf[1];
|
||||
buf[0] = p;
|
||||
static volatile void* global = buf;
|
||||
if (global) {
|
||||
global = buf;
|
||||
overflow_stack(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CrasherTest, stack_overflow) {
|
||||
int intercept_result;
|
||||
unique_fd output_fd;
|
||||
StartProcess([]() { overflow_stack(nullptr); });
|
||||
|
||||
StartIntercept(&output_fd);
|
||||
FinishCrasher();
|
||||
AssertDeath(SIGSEGV);
|
||||
FinishIntercept(&intercept_result);
|
||||
|
||||
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
|
||||
|
||||
std::string result;
|
||||
ConsumeFd(std::move(output_fd), &result);
|
||||
ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
|
||||
}
|
||||
|
|
|
@ -86,7 +86,39 @@ static void dump_timestamp(log_t* log, time_t time) {
|
|||
_LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
|
||||
}
|
||||
|
||||
static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) {
|
||||
static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp,
|
||||
unwindstack::Maps* maps) {
|
||||
static constexpr uint64_t kMaxDifferenceBytes = 256;
|
||||
uint64_t difference;
|
||||
if (sp >= fault_addr) {
|
||||
difference = sp - fault_addr;
|
||||
} else {
|
||||
difference = fault_addr - sp;
|
||||
}
|
||||
if (difference <= kMaxDifferenceBytes) {
|
||||
// The faulting address is close to the current sp, check if the sp
|
||||
// indicates a stack overflow.
|
||||
// On arm, the sp does not get updated when the instruction faults.
|
||||
// In this case, the sp will still be in a valid map, which is the
|
||||
// last case below.
|
||||
// On aarch64, the sp does get updated when the instruction faults.
|
||||
// In this case, the sp will be in either an invalid map if triggered
|
||||
// on the main thread, or in a guard map if in another thread, which
|
||||
// will be the first case or second case from below.
|
||||
unwindstack::MapInfo* map_info = maps->Find(sp);
|
||||
if (map_info == nullptr) {
|
||||
return "stack pointer is in a non-existent map; likely due to stack overflow.";
|
||||
} else if ((map_info->flags & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
|
||||
return "stack pointer is not in a rw map; likely due to stack overflow.";
|
||||
} else if ((sp - map_info->start) <= kMaxDifferenceBytes) {
|
||||
return "stack pointer is close to top of stack; likely stack overflow.";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps,
|
||||
unwindstack::Regs* regs) {
|
||||
std::string cause;
|
||||
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
|
||||
if (si->si_addr < reinterpret_cast<void*>(4096)) {
|
||||
|
@ -101,11 +133,16 @@ static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Ma
|
|||
cause = "call to kuser_memory_barrier";
|
||||
} else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
|
||||
cause = "call to kuser_cmpxchg64";
|
||||
} else {
|
||||
cause = get_stack_overflow_cause(reinterpret_cast<uint64_t>(si->si_addr), regs->sp(), maps);
|
||||
}
|
||||
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
|
||||
unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr));
|
||||
uint64_t fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
|
||||
unwindstack::MapInfo* map_info = maps->Find(fault_addr);
|
||||
if (map_info != nullptr && map_info->flags == PROT_EXEC) {
|
||||
cause = "execute-only (no-read) memory access error; likely due to data in .text.";
|
||||
} else {
|
||||
cause = get_stack_overflow_cause(fault_addr, regs->sp(), maps);
|
||||
}
|
||||
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
|
||||
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
|
||||
|
@ -447,7 +484,7 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa
|
|||
|
||||
if (thread_info.siginfo) {
|
||||
dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
|
||||
dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps());
|
||||
dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(), thread_info.registers.get());
|
||||
}
|
||||
|
||||
if (primary_thread) {
|
||||
|
|
Loading…
Reference in a new issue