tsan: intercept fork() to prevent false race reports on fd's

llvm-svn: 170433
This commit is contained in:
Dmitry Vyukov 2012-12-18 14:44:44 +00:00
parent d8a08ea98d
commit 44e1beaee6
6 changed files with 36 additions and 0 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 ";

View File

@ -233,6 +233,7 @@ enum StatType {
StatInt_usleep,
StatInt_nanosleep,
StatInt_gettimeofday,
StatInt_fork,
// Dynamic annotations.
StatAnnotation,

View File

@ -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);