[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:
Evgeniy Stepanov 2014-02-19 13:40:41 +00:00
parent 150d62aa2a
commit cba008e9c5
5 changed files with 38 additions and 23 deletions

View File

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

View File

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

View File

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

View File

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

View File

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