forked from OSchip/llvm-project
parent
510ad11800
commit
4adf49d253
|
|
@ -0,0 +1,22 @@
|
||||||
|
// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
int foo(jmp_buf env) {
|
||||||
|
longjmp(env, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
jmp_buf env;
|
||||||
|
if (setjmp(env) == 42) {
|
||||||
|
printf("JUMPED\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
foo(env);
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NOT: FAILED
|
||||||
|
// CHECK: JUMPED
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
int foo(sigjmp_buf env) {
|
||||||
|
printf("env=%p\n", env);
|
||||||
|
siglongjmp(env, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
sigjmp_buf env;
|
||||||
|
printf("env=%p\n", env);
|
||||||
|
if (sigsetjmp(env, 1) == 42) {
|
||||||
|
printf("JUMPED\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
foo(env);
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NOT: FAILED
|
||||||
|
// CHECK: JUMPED
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
void bar(jmp_buf env) {
|
||||||
|
volatile int x = 42;
|
||||||
|
longjmp(env, 42);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo(jmp_buf env) {
|
||||||
|
volatile int x = 42;
|
||||||
|
bar(env);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void badguy() {
|
||||||
|
pthread_mutex_t mtx;
|
||||||
|
pthread_mutex_init(&mtx, 0);
|
||||||
|
pthread_mutex_lock(&mtx);
|
||||||
|
pthread_mutex_destroy(&mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mymain() {
|
||||||
|
jmp_buf env;
|
||||||
|
if (setjmp(env) == 42) {
|
||||||
|
badguy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foo(env);
|
||||||
|
printf("FAILED\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
volatile int x = 42;
|
||||||
|
mymain();
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NOT: FAILED
|
||||||
|
// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
|
||||||
|
// CHECK: #0 pthread_mutex_destroy
|
||||||
|
// CHECK: #1 badguy
|
||||||
|
// CHECK: #2 mymain
|
||||||
|
// CHECK: #3 main
|
||||||
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void bar(jmp_buf env) {
|
||||||
|
volatile int x = 42;
|
||||||
|
jmp_buf env2;
|
||||||
|
memcpy(env2, env, sizeof(jmp_buf));
|
||||||
|
longjmp(env2, 42);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo(jmp_buf env) {
|
||||||
|
volatile int x = 42;
|
||||||
|
bar(env);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void badguy() {
|
||||||
|
pthread_mutex_t mtx;
|
||||||
|
pthread_mutex_init(&mtx, 0);
|
||||||
|
pthread_mutex_lock(&mtx);
|
||||||
|
pthread_mutex_destroy(&mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mymain() {
|
||||||
|
jmp_buf env;
|
||||||
|
if (setjmp(env) == 42) {
|
||||||
|
badguy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foo(env);
|
||||||
|
printf("FAILED\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
volatile int x = 42;
|
||||||
|
mymain();
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NOT: FAILED
|
||||||
|
// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
|
||||||
|
// CHECK: #0 pthread_mutex_destroy
|
||||||
|
// CHECK: #1 badguy
|
||||||
|
// CHECK: #2 mymain
|
||||||
|
// CHECK: #3 main
|
||||||
|
|
||||||
|
|
@ -319,16 +319,98 @@ TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
|
||||||
return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
|
return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
|
// Cleanup old bufs.
|
||||||
SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
|
static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
|
||||||
Printf("ThreadSanitizer: longjmp() is not supported\n");
|
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
|
||||||
Die();
|
JmpBuf *buf = &thr->jmp_bufs[i];
|
||||||
|
if (buf->sp <= sp) {
|
||||||
|
uptr sz = thr->jmp_bufs.Size();
|
||||||
|
thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1];
|
||||||
|
thr->jmp_bufs.PopBack();
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TSAN_INTERCEPTOR(void, siglongjmp, void *env, int val) {
|
static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
|
||||||
SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
|
if (thr->shadow_stack_pos == 0) // called from libc guts during bootstrap
|
||||||
Printf("ThreadSanitizer: siglongjmp() is not supported\n");
|
return;
|
||||||
Die();
|
// Cleanup old bufs.
|
||||||
|
JmpBufGarbageCollect(thr, sp);
|
||||||
|
// Remember the buf.
|
||||||
|
JmpBuf *buf = thr->jmp_bufs.PushBack();
|
||||||
|
buf->sp = sp;
|
||||||
|
buf->mangled_sp = mangled_sp;
|
||||||
|
buf->shadow_stack_pos = thr->shadow_stack_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LongJmp(ThreadState *thr, uptr *env) {
|
||||||
|
uptr mangled_sp = env[6];
|
||||||
|
// Find the saved buf by mangled_sp.
|
||||||
|
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
|
||||||
|
JmpBuf *buf = &thr->jmp_bufs[i];
|
||||||
|
if (buf->mangled_sp == mangled_sp) {
|
||||||
|
CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos);
|
||||||
|
// Unwind the stack.
|
||||||
|
while (thr->shadow_stack_pos > buf->shadow_stack_pos)
|
||||||
|
FuncExit(thr);
|
||||||
|
JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Printf("ThreadSanitizer: can't find longjmp buf\n");
|
||||||
|
CHECK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
|
||||||
|
ScopedInRtl in_rtl;
|
||||||
|
SetJmp(cur_thread(), sp, mangled_sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not called. Merely to satisfy TSAN_INTERCEPT().
|
||||||
|
extern "C" int __interceptor_setjmp(void *env) {
|
||||||
|
CHECK(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int __interceptor__setjmp(void *env) {
|
||||||
|
CHECK(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int __interceptor_sigsetjmp(void *env) {
|
||||||
|
CHECK(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int __interceptor___sigsetjmp(void *env) {
|
||||||
|
CHECK(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int setjmp(void *env);
|
||||||
|
extern "C" int _setjmp(void *env);
|
||||||
|
extern "C" int sigsetjmp(void *env);
|
||||||
|
extern "C" int __sigsetjmp(void *env);
|
||||||
|
DEFINE_REAL(int, setjmp, void *env)
|
||||||
|
DEFINE_REAL(int, _setjmp, void *env)
|
||||||
|
DEFINE_REAL(int, sigsetjmp, void *env)
|
||||||
|
DEFINE_REAL(int, __sigsetjmp, void *env)
|
||||||
|
|
||||||
|
TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
|
||||||
|
{
|
||||||
|
SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
|
||||||
|
}
|
||||||
|
LongJmp(cur_thread(), env);
|
||||||
|
REAL(longjmp)(env, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
|
||||||
|
{
|
||||||
|
SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
|
||||||
|
}
|
||||||
|
LongJmp(cur_thread(), env);
|
||||||
|
REAL(siglongjmp)(env, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
|
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
|
||||||
|
|
@ -1853,6 +1935,10 @@ void InitializeInterceptors() {
|
||||||
|
|
||||||
SANITIZER_COMMON_INTERCEPTORS_INIT;
|
SANITIZER_COMMON_INTERCEPTORS_INIT;
|
||||||
|
|
||||||
|
TSAN_INTERCEPT(setjmp);
|
||||||
|
TSAN_INTERCEPT(_setjmp);
|
||||||
|
TSAN_INTERCEPT(sigsetjmp);
|
||||||
|
TSAN_INTERCEPT(__sigsetjmp);
|
||||||
TSAN_INTERCEPT(longjmp);
|
TSAN_INTERCEPT(longjmp);
|
||||||
TSAN_INTERCEPT(siglongjmp);
|
TSAN_INTERCEPT(siglongjmp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ enum MBlockType {
|
||||||
MBlockExpectRace,
|
MBlockExpectRace,
|
||||||
MBlockSignal,
|
MBlockSignal,
|
||||||
MBlockFD,
|
MBlockFD,
|
||||||
|
MBlockJmpBuf,
|
||||||
|
|
||||||
// This must be the last.
|
// This must be the last.
|
||||||
MBlockTypeCount
|
MBlockTypeCount
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
|
||||||
// , fast_ignore_writes()
|
// , fast_ignore_writes()
|
||||||
// , in_rtl()
|
// , in_rtl()
|
||||||
, shadow_stack_pos(&shadow_stack[0])
|
, shadow_stack_pos(&shadow_stack[0])
|
||||||
|
#ifndef TSAN_GO
|
||||||
|
, jmp_bufs(MBlockJmpBuf)
|
||||||
|
#endif
|
||||||
, tid(tid)
|
, tid(tid)
|
||||||
, unique_id(unique_id)
|
, unique_id(unique_id)
|
||||||
, stk_addr(stk_addr)
|
, stk_addr(stk_addr)
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,12 @@ class Shadow : public FastState {
|
||||||
|
|
||||||
struct SignalContext;
|
struct SignalContext;
|
||||||
|
|
||||||
|
struct JmpBuf {
|
||||||
|
uptr sp;
|
||||||
|
uptr mangled_sp;
|
||||||
|
uptr *shadow_stack_pos;
|
||||||
|
};
|
||||||
|
|
||||||
// This struct is stored in TLS.
|
// This struct is stored in TLS.
|
||||||
struct ThreadState {
|
struct ThreadState {
|
||||||
FastState fast_state;
|
FastState fast_state;
|
||||||
|
|
@ -418,6 +424,7 @@ struct ThreadState {
|
||||||
ThreadClock clock;
|
ThreadClock clock;
|
||||||
#ifndef TSAN_GO
|
#ifndef TSAN_GO
|
||||||
AllocatorCache alloc_cache;
|
AllocatorCache alloc_cache;
|
||||||
|
Vector<JmpBuf> jmp_bufs;
|
||||||
#endif
|
#endif
|
||||||
u64 stat[StatCnt];
|
u64 stat[StatCnt];
|
||||||
const int tid;
|
const int tid;
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,143 @@ __tsan_report_race_thunk:
|
||||||
ret
|
ret
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
|
|
||||||
|
.hidden __tsan_setjmp
|
||||||
|
.comm _ZN14__interception11real_setjmpE,8,8
|
||||||
|
.globl setjmp
|
||||||
|
.type setjmp, @function
|
||||||
|
setjmp:
|
||||||
|
.cfi_startproc
|
||||||
|
// save env parameter
|
||||||
|
push %rdi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rdi, 0
|
||||||
|
// obtain %rsp
|
||||||
|
lea 16(%rsp), %rdi
|
||||||
|
mov %rdi, %rsi
|
||||||
|
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
|
||||||
|
rol $0x11, %rsi
|
||||||
|
// call tsan interceptor
|
||||||
|
call __tsan_setjmp
|
||||||
|
// restore env parameter
|
||||||
|
pop %rdi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rdi
|
||||||
|
// tail jump to libc setjmp
|
||||||
|
movl $0, %eax
|
||||||
|
movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
|
||||||
|
jmp *(%rdx)
|
||||||
|
.cfi_endproc
|
||||||
|
.size setjmp, .-setjmp
|
||||||
|
|
||||||
|
.comm _ZN14__interception12real__setjmpE,8,8
|
||||||
|
.globl _setjmp
|
||||||
|
.type _setjmp, @function
|
||||||
|
_setjmp:
|
||||||
|
.cfi_startproc
|
||||||
|
// save env parameter
|
||||||
|
push %rdi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rdi, 0
|
||||||
|
// obtain %rsp
|
||||||
|
lea 16(%rsp), %rdi
|
||||||
|
mov %rdi, %rsi
|
||||||
|
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
|
||||||
|
rol $0x11, %rsi
|
||||||
|
// call tsan interceptor
|
||||||
|
call __tsan_setjmp
|
||||||
|
// restore env parameter
|
||||||
|
pop %rdi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rdi
|
||||||
|
// tail jump to libc setjmp
|
||||||
|
movl $0, %eax
|
||||||
|
movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
|
||||||
|
jmp *(%rdx)
|
||||||
|
.cfi_endproc
|
||||||
|
.size _setjmp, .-_setjmp
|
||||||
|
|
||||||
|
.comm _ZN14__interception14real_sigsetjmpE,8,8
|
||||||
|
.globl sigsetjmp
|
||||||
|
.type sigsetjmp, @function
|
||||||
|
sigsetjmp:
|
||||||
|
.cfi_startproc
|
||||||
|
// save env parameter
|
||||||
|
push %rdi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rdi, 0
|
||||||
|
// save savesigs parameter
|
||||||
|
push %rsi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rsi, 0
|
||||||
|
// align stack frame
|
||||||
|
sub $8, %rsp
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
// obtain %rsp
|
||||||
|
lea 32(%rsp), %rdi
|
||||||
|
mov %rdi, %rsi
|
||||||
|
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
|
||||||
|
rol $0x11, %rsi
|
||||||
|
// call tsan interceptor
|
||||||
|
call __tsan_setjmp
|
||||||
|
// unalign stack frame
|
||||||
|
add $8, %rsp
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
// restore savesigs parameter
|
||||||
|
pop %rsi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rsi
|
||||||
|
// restore env parameter
|
||||||
|
pop %rdi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rdi
|
||||||
|
// tail jump to libc sigsetjmp
|
||||||
|
movl $0, %eax
|
||||||
|
movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
|
||||||
|
jmp *(%rdx)
|
||||||
|
.cfi_endproc
|
||||||
|
.size sigsetjmp, .-sigsetjmp
|
||||||
|
|
||||||
|
.comm _ZN14__interception16real___sigsetjmpE,8,8
|
||||||
|
.globl __sigsetjmp
|
||||||
|
.type __sigsetjmp, @function
|
||||||
|
__sigsetjmp:
|
||||||
|
.cfi_startproc
|
||||||
|
// save env parameter
|
||||||
|
push %rdi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rdi, 0
|
||||||
|
// save savesigs parameter
|
||||||
|
push %rsi
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
.cfi_rel_offset %rsi, 0
|
||||||
|
// align stack frame
|
||||||
|
sub $8, %rsp
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
// obtain %rsp
|
||||||
|
lea 32(%rsp), %rdi
|
||||||
|
mov %rdi, %rsi
|
||||||
|
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
|
||||||
|
rol $0x11, %rsi
|
||||||
|
// call tsan interceptor
|
||||||
|
call __tsan_setjmp
|
||||||
|
// unalign stack frame
|
||||||
|
add $8, %rsp
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
// restore savesigs parameter
|
||||||
|
pop %rsi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rsi
|
||||||
|
// restore env parameter
|
||||||
|
pop %rdi
|
||||||
|
.cfi_adjust_cfa_offset -8
|
||||||
|
.cfi_restore %rdi
|
||||||
|
// tail jump to libc sigsetjmp
|
||||||
|
movl $0, %eax
|
||||||
|
movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
|
||||||
|
jmp *(%rdx)
|
||||||
|
.cfi_endproc
|
||||||
|
.size __sigsetjmp, .-__sigsetjmp
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/* We do not need executable stack. */
|
/* We do not need executable stack. */
|
||||||
.section .note.GNU-stack,"",@progbits
|
.section .note.GNU-stack,"",@progbits
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,11 @@ class Vector {
|
||||||
return &end_[-1];
|
return &end_[-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PopBack() {
|
||||||
|
DCHECK_GT(end_, begin_);
|
||||||
|
end_--;
|
||||||
|
}
|
||||||
|
|
||||||
void Resize(uptr size) {
|
void Resize(uptr size) {
|
||||||
uptr old_size = Size();
|
uptr old_size = Size();
|
||||||
EnsureSize(size);
|
EnsureSize(size);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue