tsan: support longjmp out of signal handlers

Fixes https://code.google.com/p/thread-sanitizer/issues/detail?id=75

llvm-svn: 217908
This commit is contained in:
Dmitry Vyukov 2014-09-16 21:48:22 +00:00
parent cca43c15b5
commit 69c4d37b45
3 changed files with 78 additions and 0 deletions

View File

@ -390,6 +390,11 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
buf->sp = sp;
buf->mangled_sp = mangled_sp;
buf->shadow_stack_pos = thr->shadow_stack_pos;
SignalContext *sctx = SigCtx(thr);
buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
buf->in_blocking_func = sctx ? sctx->in_blocking_func : false;
buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
memory_order_relaxed);
}
static void LongJmp(ThreadState *thr, uptr *env) {
@ -402,6 +407,13 @@ static void LongJmp(ThreadState *thr, uptr *env) {
// Unwind the stack.
while (thr->shadow_stack_pos > buf->shadow_stack_pos)
FuncExit(thr);
SignalContext *sctx = SigCtx(thr);
if (sctx) {
sctx->int_signal_send = buf->int_signal_send;
sctx->in_blocking_func = buf->in_blocking_func;
}
atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
memory_order_relaxed);
JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp
return;
}

View File

@ -308,6 +308,9 @@ struct SignalContext;
struct JmpBuf {
uptr sp;
uptr mangled_sp;
int int_signal_send;
bool in_blocking_func;
uptr in_signal_handler;
uptr *shadow_stack_pos;
};

View File

@ -0,0 +1,63 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// Test case for longjumping out of signal handler:
// https://code.google.com/p/thread-sanitizer/issues/detail?id=71
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
sigjmp_buf fault_jmp;
volatile int fault_expected;
void sigfault_handler(int sig) {
if (!fault_expected)
abort();
/* just return from sighandler to proper place */
fault_expected = 0;
siglongjmp(fault_jmp, 1);
}
#define MUST_FAULT(code) do { \
fault_expected = 1; \
if (!sigsetjmp(fault_jmp, 1)) { \
code; /* should pagefault -> sihandler does longjmp */ \
fprintf(stderr, "%s not faulted\n", #code); \
abort(); \
} else { \
fprintf(stderr, "%s faulted ok\n", #code); \
} \
} while (0)
int main() {
struct sigaction act;
act.sa_handler = sigfault_handler;
act.sa_flags = 0;
if (sigemptyset(&act.sa_mask)) {
perror("sigemptyset");
exit(1);
}
if (sigaction(SIGSEGV, &act, NULL)) {
perror("sigaction");
exit(1);
}
MUST_FAULT(((volatile int *volatile)0)[0] = 0);
MUST_FAULT(((volatile int *volatile)0)[1] = 1);
MUST_FAULT(((volatile int *volatile)0)[3] = 1);
// Ensure that tsan does not think that we are
// in a signal handler.
void *volatile p = malloc(10);
((volatile int*)p)[1] = 1;
free((void*)p);
fprintf(stderr, "DONE\n");
return 0;
}
// CHECK-NOT: WARNING: ThreadSanitizer
// CHECK: DONE