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.

llvm-svn: 154092
This commit is contained in:
Alexander Potapenko 2012-04-05 10:54:52 +00:00
parent 44016da83f
commit 08342aa1a1
5 changed files with 53 additions and 1 deletions

View File

@ -181,6 +181,8 @@ size_t AsanWrite(int fd, const void *buf, size_t count);
int AsanClose(int fd);
bool AsanInterceptsSignal(int signum);
void SetAlternateSignalStack();
void UnsetAlternateSignalStack();
void InstallSignalHandlers();
int GetPid();
uintptr_t GetThreadSelf();
@ -249,6 +251,7 @@ extern int FLAG_exitcode;
extern bool FLAG_allow_user_poisoning;
extern int FLAG_sleep_before_dying;
extern bool FLAG_handle_segv;
extern bool FLAG_use_sigaltstack;
extern int asan_inited;
// Used to avoid infinite recursion in __asan_init().

View File

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

View File

@ -39,6 +39,7 @@ int FLAG_report_globals;
size_t FLAG_malloc_context_size = kMallocContextSize;
uintptr_t FLAG_large_malloc;
bool FLAG_handle_segv;
bool FLAG_use_sigaltstack;
bool FLAG_replace_str;
bool FLAG_replace_intrin;
bool FLAG_replace_cfallocator; // Used on Mac only.
@ -442,6 +443,7 @@ void __asan_init() {
FLAG_poison_shadow = IntFlagValue(options, "poison_shadow=", 1);
FLAG_report_globals = IntFlagValue(options, "report_globals=", 1);
FLAG_handle_segv = IntFlagValue(options, "handle_segv=", ASAN_NEEDS_SEGV);
FLAG_use_sigaltstack = IntFlagValue(options, "use_sigaltstack=", 0);
FLAG_symbolize = IntFlagValue(options, "symbolize=", 1);
FLAG_demangle = IntFlagValue(options, "demangle=", 1);
FLAG_debug = IntFlagValue(options, "debug=", 0);
@ -470,7 +472,6 @@ void __asan_init() {
InitializeAsanInterceptors();
ReplaceSystemMalloc();
InstallSignalHandlers();
if (FLAG_v) {
Printf("|| `[%p, %p]` || HighMem ||\n", kHighMemBeg, kHighMemEnd);
@ -517,6 +518,8 @@ void __asan_init() {
AsanDie();
}
InstallSignalHandlers();
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
asan_inited = 1;

View File

@ -82,6 +82,7 @@ void AsanThread::Init() {
thread_return_t AsanThread::ThreadStart() {
Init();
if (FLAG_use_sigaltstack) SetAlternateSignalStack();
if (!start_routine_) {
// start_routine_ == NULL if we're on the main thread or on one of the
@ -93,6 +94,7 @@ thread_return_t AsanThread::ThreadStart() {
thread_return_t res = start_routine_(arg_);
malloc_storage().CommitBack();
if (FLAG_use_sigaltstack) UnsetAlternateSignalStack();
this->Destroy();

View File

@ -262,6 +262,14 @@ uintptr_t GetThreadSelf() {
return GetCurrentThreadId();
}
void SetAlternateSignalStack() {
// FIXME: Decide what to do on Windows.
}
void UnsetAlternateSignalStack() {
// FIXME: Decide what to do on Windows.
}
void InstallSignalHandlers() {
// FIXME: Decide what to do on Windows.
}