diff options
author | Alexander Potapenko <glider@google.com> | 2012-04-05 10:54:52 +0000 |
---|---|---|
committer | Alexander Potapenko <glider@google.com> | 2012-04-05 10:54:52 +0000 |
commit | f03d8afc8b8dd072c4e2884a7475ee28ac5f3f41 (patch) | |
tree | d9e479e5320e01b6b8a2355522a78b46d2c06f3f /lib/asan/asan_posix.cc | |
parent | adf331e82ff0f02f68eb3aabd94f9bbd46f94dd0 (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.cc | 36 |
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); } |