forked from OSchip/llvm-project
[asan] A different way of detectinb stack overflow.
Instead of checking stack limits that are not well defined for the main thread, we rely on siginfo::si_code and distance from SP. llvm-svn: 201673
This commit is contained in:
parent
150d62aa2a
commit
cba008e9c5
|
@ -34,11 +34,23 @@ namespace __asan {
|
|||
|
||||
void AsanOnSIGSEGV(int, void *siginfo, void *context) {
|
||||
uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
|
||||
int code = (int)((siginfo_t*)siginfo)->si_code;
|
||||
// Write the first message using the bullet-proof write.
|
||||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||
uptr pc, sp, bp;
|
||||
GetPcSpBp(context, &pc, &sp, &bp);
|
||||
ReportSIGSEGV(pc, sp, bp, context, addr);
|
||||
|
||||
// Access at a reasonable offset above SP, or slightly below it (to account
|
||||
// for x86_64 redzone, ARM push of multiple registers, etc) is probably a
|
||||
// stack overflow.
|
||||
// We also check si_code to filter out SEGV caused by something else other
|
||||
// then hitting the guard page or unmapped memory, like, for example,
|
||||
// unaligned memory access.
|
||||
if (addr + 128 > sp && addr < sp + 0xFFFF &&
|
||||
(code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
|
||||
ReportStackOverflow(pc, sp, bp, context, addr);
|
||||
else
|
||||
ReportSIGSEGV(pc, sp, bp, context, addr);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
|
|
@ -568,40 +568,35 @@ class ScopedInErrorReport {
|
|||
}
|
||||
};
|
||||
|
||||
static bool IsStackOverflow(uptr addr, uptr sp) {
|
||||
uptr stack_frame_bottom = sp;
|
||||
// x86_64 stack redzone: leaf functions can access up to 128 bytes below SP.
|
||||
// ARM has push-multiple instruction that stores up to 64(?) bytes below SP.
|
||||
stack_frame_bottom -= 128;
|
||||
|
||||
// Access below SP (minus redzone) is probably something else (like stack of
|
||||
// another thread).
|
||||
if (addr < stack_frame_bottom)
|
||||
return false;
|
||||
|
||||
AsanThread *t = GetCurrentThread();
|
||||
// Anything below stack_bottom, but not too far away is a stack overflow.
|
||||
// Bottom 4k may be a guard page. Treat it as stack-overflow as well.
|
||||
return addr < t->stack_bottom() + GetPageSizeCached() &&
|
||||
addr > t->stack_bottom() - 0xFFFF;
|
||||
void ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
|
||||
ScopedInErrorReport in_report;
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: stack-overflow on address %p"
|
||||
" (pc %p sp %p bp %p T%d)\n",
|
||||
(void *)addr, (void *)pc, (void *)sp, (void *)bp,
|
||||
GetCurrentTidOrInvalid());
|
||||
Printf("%s", d.EndWarning());
|
||||
GET_STACK_TRACE_SIGNAL(pc, bp, context);
|
||||
stack.Print();
|
||||
ReportErrorSummary("stack-overflow", &stack);
|
||||
}
|
||||
|
||||
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
|
||||
ScopedInErrorReport in_report;
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
bool stack_overflow = IsStackOverflow(addr, sp);
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: %s %p"
|
||||
"ERROR: AddressSanitizer: SEGV on unknown address %p"
|
||||
" (pc %p sp %p bp %p T%d)\n",
|
||||
stack_overflow ? "stack-overflow on address" : "SEGV on unknown address",
|
||||
(void *)addr, (void *)pc, (void *)sp, (void *)bp,
|
||||
GetCurrentTidOrInvalid());
|
||||
Printf("%s", d.EndWarning());
|
||||
GET_STACK_TRACE_SIGNAL(pc, bp, context);
|
||||
stack.Print();
|
||||
Printf("AddressSanitizer can not provide additional info.\n");
|
||||
ReportErrorSummary(stack_overflow ? "stack-overflow" : "SEGV", &stack);
|
||||
ReportErrorSummary("SEGV", &stack);
|
||||
}
|
||||
|
||||
void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
|
||||
|
|
|
@ -32,6 +32,8 @@ void DescribeAddress(uptr addr, uptr access_size);
|
|||
void DescribeThread(AsanThreadContext *context);
|
||||
|
||||
// Different kinds of error reports.
|
||||
void NORETURN
|
||||
ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
|
||||
void NORETURN
|
||||
ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
|
||||
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
|
||||
|
|
|
@ -772,10 +772,13 @@ namespace __sanitizer {
|
|||
const int errno_EINVAL = EINVAL;
|
||||
// EOWNERDEAD is not present in some older platforms.
|
||||
#if defined(EOWNERDEAD)
|
||||
extern const int errno_EOWNERDEAD = EOWNERDEAD;
|
||||
const int errno_EOWNERDEAD = EOWNERDEAD;
|
||||
#else
|
||||
extern const int errno_EOWNERDEAD = -1;
|
||||
const int errno_EOWNERDEAD = -1;
|
||||
#endif
|
||||
|
||||
const int si_SEGV_MAPERR = SEGV_MAPERR;
|
||||
const int si_SEGV_ACCERR = SEGV_ACCERR;
|
||||
} // namespace __sanitizer
|
||||
|
||||
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
|
||||
|
|
|
@ -1054,6 +1054,9 @@ namespace __sanitizer {
|
|||
|
||||
extern const int errno_EINVAL;
|
||||
extern const int errno_EOWNERDEAD;
|
||||
|
||||
extern const int si_SEGV_MAPERR;
|
||||
extern const int si_SEGV_ACCERR;
|
||||
} // namespace __sanitizer
|
||||
|
||||
#define CHECK_TYPE_SIZE(TYPE) \
|
||||
|
|
Loading…
Reference in New Issue