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:
parent
cca43c15b5
commit
69c4d37b45
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue