forked from OSchip/llvm-project
[compiler-rt] Move IsStackOverflow from asan into sanitizer_common
Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D37536 llvm-svn: 312951
This commit is contained in:
parent
36266b6b0d
commit
ecba46d0e6
|
@ -35,56 +35,13 @@ namespace __asan {
|
|||
|
||||
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
|
||||
ScopedDeadlySignal signal_scope(GetCurrentThread());
|
||||
int code = (int)((siginfo_t*)siginfo)->si_code;
|
||||
// Write the first message using fd=2, just in case.
|
||||
// It may actually fail to write in case stderr is closed.
|
||||
internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName));
|
||||
static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
|
||||
internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1);
|
||||
SignalContext sig = SignalContext::Create(siginfo, context);
|
||||
|
||||
// Access at a reasonable offset above SP, or slightly below it (to account
|
||||
// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
|
||||
// probably a stack overflow.
|
||||
#ifdef __s390__
|
||||
// On s390, the fault address in siginfo points to start of the page, not
|
||||
// to the precise word that was accessed. Mask off the low bits of sp to
|
||||
// take it into account.
|
||||
bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
|
||||
sig.addr < sig.sp + 0xFFFF;
|
||||
#else
|
||||
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
|
||||
#endif
|
||||
|
||||
#if __powerpc__
|
||||
// Large stack frames can be allocated with e.g.
|
||||
// lis r0,-10000
|
||||
// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
|
||||
// If the store faults then sp will not have been updated, so test above
|
||||
// will not work, because the fault address will be more than just "slightly"
|
||||
// below sp.
|
||||
if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
|
||||
u32 inst = *(unsigned *)sig.pc;
|
||||
u32 ra = (inst >> 16) & 0x1F;
|
||||
u32 opcd = inst >> 26;
|
||||
u32 xo = (inst >> 1) & 0x3FF;
|
||||
// Check for store-with-update to sp. The instructions we accept are:
|
||||
// stbu rs,d(ra) stbux rs,ra,rb
|
||||
// sthu rs,d(ra) sthux rs,ra,rb
|
||||
// stwu rs,d(ra) stwux rs,ra,rb
|
||||
// stdu rs,ds(ra) stdux rs,ra,rb
|
||||
// where ra is r1 (the stack pointer).
|
||||
if (ra == 1 &&
|
||||
(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
|
||||
(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
|
||||
IsStackAccess = true;
|
||||
}
|
||||
#endif // __powerpc__
|
||||
|
||||
// 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 (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
|
||||
if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig))
|
||||
ReportStackOverflow(sig);
|
||||
else
|
||||
ReportDeadlySignal(signo, sig);
|
||||
|
|
|
@ -306,6 +306,7 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
|
|||
// Functions related to signal handling.
|
||||
typedef void (*SignalHandlerType)(int, void *, void *);
|
||||
HandleSignalMode GetHandleSignalMode(int signum);
|
||||
bool IsStackOverflow(int code, const struct SignalContext &sig);
|
||||
void InstallDeadlySignalHandlers(SignalHandlerType handler);
|
||||
const char *DescribeSignalOrException(int signo);
|
||||
// Alternative signal stack (POSIX-only).
|
||||
|
|
|
@ -321,6 +321,53 @@ const char *DescribeSignalOrException(int signo) {
|
|||
return "UNKNOWN SIGNAL";
|
||||
}
|
||||
|
||||
#if !SANITIZER_GO
|
||||
bool IsStackOverflow(int code, const SignalContext &sig) {
|
||||
// Access at a reasonable offset above SP, or slightly below it (to account
|
||||
// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
|
||||
// probably a stack overflow.
|
||||
#ifdef __s390__
|
||||
// On s390, the fault address in siginfo points to start of the page, not
|
||||
// to the precise word that was accessed. Mask off the low bits of sp to
|
||||
// take it into account.
|
||||
bool IsStackAccess =
|
||||
sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF;
|
||||
#else
|
||||
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
|
||||
#endif
|
||||
|
||||
#if __powerpc__
|
||||
// Large stack frames can be allocated with e.g.
|
||||
// lis r0,-10000
|
||||
// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
|
||||
// If the store faults then sp will not have been updated, so test above
|
||||
// will not work, because the fault address will be more than just "slightly"
|
||||
// below sp.
|
||||
if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
|
||||
u32 inst = *(unsigned *)sig.pc;
|
||||
u32 ra = (inst >> 16) & 0x1F;
|
||||
u32 opcd = inst >> 26;
|
||||
u32 xo = (inst >> 1) & 0x3FF;
|
||||
// Check for store-with-update to sp. The instructions we accept are:
|
||||
// stbu rs,d(ra) stbux rs,ra,rb
|
||||
// sthu rs,d(ra) sthux rs,ra,rb
|
||||
// stwu rs,d(ra) stwux rs,ra,rb
|
||||
// stdu rs,ds(ra) stdux rs,ra,rb
|
||||
// where ra is r1 (the stack pointer).
|
||||
if (ra == 1 &&
|
||||
(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
|
||||
(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
|
||||
IsStackAccess = true;
|
||||
}
|
||||
#endif // __powerpc__
|
||||
|
||||
// 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.
|
||||
return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR);
|
||||
}
|
||||
#endif //! SANITIZER_GO
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_POSIX
|
||||
|
|
Loading…
Reference in New Issue