summaryrefslogtreecommitdiff
path: root/lib/asan/asan_posix.cc
diff options
context:
space:
mode:
authorJay Foad <jay.foad@gmail.com>2014-11-14 15:30:39 +0000
committerJay Foad <jay.foad@gmail.com>2014-11-14 15:30:39 +0000
commitfd35da53328612f687c78d4af0d8546e3befc1e6 (patch)
tree653f5151ca18217648e1a923b2a77cabc2bfaf98 /lib/asan/asan_posix.cc
parent850ccaad05a80d95a122e0b873a87ac924dbf759 (diff)
[ASan] Improved stack overflow detection for PowerPC64
Summary: AsanOnSIGSEGV has some heuristics for detecting stack overflow, but they don't cope with a PowerPC store-with-update instruction which modifies sp and stores to the modified address in one instruction. This patch adds some PowerPC-specific code to check for this case. This fixes the last few cases of the stack-overflow test. Reviewers: kcc, samsonov, eugenis Reviewed By: eugenis Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6253 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@222001 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan/asan_posix.cc')
-rw-r--r--lib/asan/asan_posix.cc30
1 files changed, 28 insertions, 2 deletions
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index b247ce32a..7b4db8736 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -44,11 +44,37 @@ void AsanOnSIGSEGV(int, void *siginfo, void *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.
+ bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF;
+
+#if __powerpc64__
+ // 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, becase the fault address will be more than just "slightly"
+ // below sp.
+ if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) {
+ u32 inst = *(unsigned *)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 // __powerpc64__
+
// 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 + 512 > sp && addr < sp + 0xFFFF &&
- (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
+ if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(pc, sp, bp, context, addr);
else
ReportSIGSEGV("SEGV", pc, sp, bp, context, addr);