forked from OSchip/llvm-project
tsan: intercept fork() to prevent false race reports on fd's
llvm-svn: 170433
This commit is contained in:
parent
d8a08ea98d
commit
44e1beaee6
|
@ -114,6 +114,21 @@ void FdInit() {
|
|||
atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void FdOnFork(ThreadState *thr, uptr pc) {
|
||||
// On fork() we need to reset all fd's, because the child is going
|
||||
// close all them, and that will cause races between previous read/write
|
||||
// and the close.
|
||||
for (int l1 = 0; l1 < kTableSizeL1; l1++) {
|
||||
FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
|
||||
if (tab == 0)
|
||||
break;
|
||||
for (int l2 = 0; l2 < kTableSizeL2; l2++) {
|
||||
FdDesc *d = &tab[l2];
|
||||
MemoryResetRange(thr, pc, (uptr)d, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) {
|
||||
for (int l1 = 0; l1 < kTableSizeL1; l1++) {
|
||||
FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
|
||||
|
|
|
@ -54,6 +54,7 @@ void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd);
|
|||
void FdSocketConnecting(ThreadState *thr, uptr pc, int fd);
|
||||
void FdSocketConnect(ThreadState *thr, uptr pc, int fd);
|
||||
bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack);
|
||||
void FdOnFork(ThreadState *thr, uptr pc);
|
||||
|
||||
uptr File2addr(char *path);
|
||||
uptr Dir2addr(char *path);
|
||||
|
|
|
@ -1617,6 +1617,19 @@ TSAN_INTERCEPTOR(int, munlockall, void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, fork) {
|
||||
SCOPED_TSAN_INTERCEPTOR(fork);
|
||||
// It's intercepted merely to process pending signals.
|
||||
int pid = REAL(fork)();
|
||||
if (pid == 0) {
|
||||
// child
|
||||
FdOnFork(thr, pc);
|
||||
} else if (pid > 0) {
|
||||
// parent
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
void ProcessPendingSignals(ThreadState *thr) {
|
||||
|
@ -1826,6 +1839,8 @@ void InitializeInterceptors() {
|
|||
TSAN_INTERCEPT(mlockall);
|
||||
TSAN_INTERCEPT(munlockall);
|
||||
|
||||
TSAN_INTERCEPT(fork);
|
||||
|
||||
// Need to setup it, because interceptors check that the function is resolved.
|
||||
// But atexit is emitted directly into the module, so can't be resolved.
|
||||
REAL(atexit) = (int(*)(void(*)()))unreachable;
|
||||
|
|
|
@ -234,6 +234,7 @@ void StatOutput(u64 *stat) {
|
|||
name[StatInt_usleep] = " usleep ";
|
||||
name[StatInt_nanosleep] = " nanosleep ";
|
||||
name[StatInt_gettimeofday] = " gettimeofday ";
|
||||
name[StatInt_fork] = " fork ";
|
||||
|
||||
name[StatAnnotation] = "Dynamic annotations ";
|
||||
name[StatAnnotateHappensBefore] = " HappensBefore ";
|
||||
|
|
|
@ -233,6 +233,7 @@ enum StatType {
|
|||
StatInt_usleep,
|
||||
StatInt_nanosleep,
|
||||
StatInt_gettimeofday,
|
||||
StatInt_fork,
|
||||
|
||||
// Dynamic annotations.
|
||||
StatAnnotation,
|
||||
|
|
|
@ -60,6 +60,9 @@ SyncVar* SyncTab::GetIfExistsAndLock(uptr addr, bool write_lock) {
|
|||
SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
|
||||
uptr addr, bool write_lock, bool create) {
|
||||
#ifndef TSAN_GO
|
||||
// Here we ask only PrimaryAllocator, because
|
||||
// SecondaryAllocator::PointerIsMine() is slow and we have fallback on
|
||||
// the hashmap anyway.
|
||||
if (PrimaryAllocator::PointerIsMine((void*)addr)) {
|
||||
MBlock *b = user_mblock(thr, (void*)addr);
|
||||
Lock l(&b->mtx);
|
||||
|
|
Loading…
Reference in New Issue