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);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
|
||||
SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
|
||||
Printf("ThreadSanitizer: longjmp() is not supported\n");
|
||||
Die();
|
||||
// Cleanup old bufs.
|
||||
static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
|
||||
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
|
||||
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) {
|
||||
SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
|
||||
Printf("ThreadSanitizer: siglongjmp() is not supported\n");
|
||||
Die();
|
||||
static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
|
||||
if (thr->shadow_stack_pos == 0) // called from libc guts during bootstrap
|
||||
return;
|
||||
// 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) {
|
||||
|
|
@ -1853,6 +1935,10 @@ void InitializeInterceptors() {
|
|||
|
||||
SANITIZER_COMMON_INTERCEPTORS_INIT;
|
||||
|
||||
TSAN_INTERCEPT(setjmp);
|
||||
TSAN_INTERCEPT(_setjmp);
|
||||
TSAN_INTERCEPT(sigsetjmp);
|
||||
TSAN_INTERCEPT(__sigsetjmp);
|
||||
TSAN_INTERCEPT(longjmp);
|
||||
TSAN_INTERCEPT(siglongjmp);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ enum MBlockType {
|
|||
MBlockExpectRace,
|
||||
MBlockSignal,
|
||||
MBlockFD,
|
||||
MBlockJmpBuf,
|
||||
|
||||
// This must be the last.
|
||||
MBlockTypeCount
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
|
|||
// , fast_ignore_writes()
|
||||
// , in_rtl()
|
||||
, shadow_stack_pos(&shadow_stack[0])
|
||||
#ifndef TSAN_GO
|
||||
, jmp_bufs(MBlockJmpBuf)
|
||||
#endif
|
||||
, tid(tid)
|
||||
, unique_id(unique_id)
|
||||
, stk_addr(stk_addr)
|
||||
|
|
|
|||
|
|
@ -384,6 +384,12 @@ class Shadow : public FastState {
|
|||
|
||||
struct SignalContext;
|
||||
|
||||
struct JmpBuf {
|
||||
uptr sp;
|
||||
uptr mangled_sp;
|
||||
uptr *shadow_stack_pos;
|
||||
};
|
||||
|
||||
// This struct is stored in TLS.
|
||||
struct ThreadState {
|
||||
FastState fast_state;
|
||||
|
|
@ -418,6 +424,7 @@ struct ThreadState {
|
|||
ThreadClock clock;
|
||||
#ifndef TSAN_GO
|
||||
AllocatorCache alloc_cache;
|
||||
Vector<JmpBuf> jmp_bufs;
|
||||
#endif
|
||||
u64 stat[StatCnt];
|
||||
const int tid;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,143 @@ __tsan_report_race_thunk:
|
|||
ret
|
||||
.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__
|
||||
/* We do not need executable stack. */
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ class Vector {
|
|||
return &end_[-1];
|
||||
}
|
||||
|
||||
void PopBack() {
|
||||
DCHECK_GT(end_, begin_);
|
||||
end_--;
|
||||
}
|
||||
|
||||
void Resize(uptr size) {
|
||||
uptr old_size = Size();
|
||||
EnsureSize(size);
|
||||
|
|
|
|||
Loading…
Reference in New Issue