summaryrefslogtreecommitdiff
path: root/lib/asan/asan_posix.cc
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2012-04-05 10:54:52 +0000
committerAlexander Potapenko <glider@google.com>2012-04-05 10:54:52 +0000
commitf03d8afc8b8dd072c4e2884a7475ee28ac5f3f41 (patch)
treed9e479e5320e01b6b8a2355522a78b46d2c06f3f /lib/asan/asan_posix.cc
parentadf331e82ff0f02f68eb3aabd94f9bbd46f94dd0 (diff)
Introduce the use_sigaltstack flag (off by default), which enables using alternate
per-thread stacks for signal handling. This allows to print more verbose error reports for stack overflows. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@154092 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan/asan_posix.cc')
-rw-r--r--lib/asan/asan_posix.cc36
1 files changed, 36 insertions, 0 deletions
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 15bdd932e..0ab09e615 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -34,6 +34,8 @@
// since most of the stuff here is inlinable.
#include <algorithm>
+static const size_t kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
+
namespace __asan {
static void MaybeInstallSigaction(int signum,
@@ -44,6 +46,7 @@ static void MaybeInstallSigaction(int signum,
REAL(memset)(&sigact, 0, sizeof(sigact));
sigact.sa_sigaction = handler;
sigact.sa_flags = SA_SIGINFO;
+ if (FLAG_use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
}
@@ -63,7 +66,40 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
ShowStatsAndAbort();
}
+void SetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ CHECK(0 == sigaltstack(NULL, &oldstack));
+ // If the alternate stack is already in place, do nothing.
+ if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
+ // TODO(glider): the mapped stack should have the MAP_STACK flag in the
+ // future. It is not required by man 2 sigaltstack now (they're using
+ // malloc()).
+ void* base = AsanMmapSomewhereOrDie(kAltStackSize, __FUNCTION__);
+ altstack.ss_sp = base;
+ altstack.ss_flags = 0;
+ altstack.ss_size = kAltStackSize;
+ CHECK(0 == sigaltstack(&altstack, NULL));
+ if (FLAG_v > 0) {
+ Report("Alternative stack for T%d set: [%p,%p)\n",
+ asanThreadRegistry().GetCurrentTidOrMinusOne(),
+ altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
+ }
+}
+
+void UnsetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ altstack.ss_sp = NULL;
+ altstack.ss_flags = SS_DISABLE;
+ altstack.ss_size = 0;
+ CHECK(0 == sigaltstack(&altstack, &oldstack));
+ AsanUnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
+}
+
void InstallSignalHandlers() {
+ // Set the alternate signal stack for the main thread.
+ // This will cause SetAlternateSignalStack to be called twice, but the stack
+ // will be actually set only once.
+ if (FLAG_use_sigaltstack) SetAlternateSignalStack();
MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
}