[llvm-commits] [compiler-rt] r170417 - in /compiler-rt/trunk/lib/tsan: lit_tests/fd_location.cc rtl/tsan_fd.cc rtl/tsan_fd.h rtl/tsan_report.cc rtl/tsan_report.h rtl/tsan_rtl_report.cc
Dmitry Vyukov
dvyukov at google.com
Mon Dec 17 22:57:35 PST 2012
Author: dvyukov
Date: Tue Dec 18 00:57:34 2012
New Revision: 170417
URL: http://llvm.org/viewvc/llvm-project?rev=170417&view=rev
Log:
tsan: describe "file descriptor" location
Added:
compiler-rt/trunk/lib/tsan/lit_tests/fd_location.cc
Modified:
compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_fd.h
compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_report.h
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
Added: compiler-rt/trunk/lib/tsan/lit_tests/fd_location.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/fd_location.cc?rev=170417&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/fd_location.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/fd_location.cc Tue Dec 18 00:57:34 2012
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ close(fds[0]);
+ close(fds[1]);
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is file descriptor {{[0-9]+}} created by main thread at:
+// CHECK: #0 pipe
+// CHECK: #1 main
+
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc?rev=170417&r1=170416&r2=170417&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc Tue Dec 18 00:57:34 2012
@@ -21,154 +21,181 @@
const int kTableSizeL2 = 1024;
const int kTableSize = kTableSizeL1 * kTableSizeL2;
-struct FdDesc {
+struct FdSync {
atomic_uint64_t rc;
};
+struct FdDesc {
+ FdSync *sync;
+ int creation_tid;
+ u32 creation_stack;
+};
+
struct FdContext {
atomic_uintptr_t tab[kTableSizeL1];
// Addresses used for synchronization.
- FdDesc globdesc;
- FdDesc filedesc;
- FdDesc sockdesc;
+ FdSync globsync;
+ FdSync filesync;
+ FdSync socksync;
u64 connectsync;
};
static FdContext fdctx;
-static FdDesc *allocdesc() {
- FdDesc *pd = (FdDesc*)internal_alloc(MBlockFD, sizeof(FdDesc));
- atomic_store(&pd->rc, 1, memory_order_relaxed);
- return pd;
-}
-
-static FdDesc *ref(FdDesc *pd) {
- if (pd && atomic_load(&pd->rc, memory_order_relaxed) != (u64)-1)
- atomic_fetch_add(&pd->rc, 1, memory_order_relaxed);
- return pd;
-}
-
-static void unref(ThreadState *thr, uptr pc, FdDesc *pd) {
- if (pd && atomic_load(&pd->rc, memory_order_relaxed) != (u64)-1) {
- if (atomic_fetch_sub(&pd->rc, 1, memory_order_acq_rel) == 1) {
- CHECK_NE(pd, &fdctx.globdesc);
- CHECK_NE(pd, &fdctx.filedesc);
- CHECK_NE(pd, &fdctx.sockdesc);
- SyncVar *s = CTX()->synctab.GetAndRemove(thr, pc, (uptr)pd);
- if (s)
- DestroyAndFree(s);
- internal_free(pd);
+static FdSync *allocsync() {
+ FdSync *s = (FdSync*)internal_alloc(MBlockFD, sizeof(FdSync));
+ atomic_store(&s->rc, 1, memory_order_relaxed);
+ return s;
+}
+
+static FdSync *ref(FdSync *s) {
+ if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1)
+ atomic_fetch_add(&s->rc, 1, memory_order_relaxed);
+ return s;
+}
+
+static void unref(ThreadState *thr, uptr pc, FdSync *s) {
+ if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) {
+ if (atomic_fetch_sub(&s->rc, 1, memory_order_acq_rel) == 1) {
+ CHECK_NE(s, &fdctx.globsync);
+ CHECK_NE(s, &fdctx.filesync);
+ CHECK_NE(s, &fdctx.socksync);
+ SyncVar *v = CTX()->synctab.GetAndRemove(thr, pc, (uptr)s);
+ if (v)
+ DestroyAndFree(v);
+ internal_free(s);
}
}
}
-static FdDesc **fdaddr(ThreadState *thr, uptr pc, int fd) {
+static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
CHECK_LT(fd, kTableSize);
atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2];
uptr l1 = atomic_load(pl1, memory_order_consume);
if (l1 == 0) {
- uptr size = kTableSizeL2 * sizeof(uptr);
+ uptr size = kTableSizeL2 * sizeof(FdDesc);
void *p = internal_alloc(MBlockFD, size);
internal_memset(p, 0, size);
- MemoryResetRange(thr, (uptr)&fdaddr, (uptr)p, size);
+ MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
l1 = (uptr)p;
else
internal_free(p);
}
- return &((FdDesc**)l1)[fd % kTableSizeL2]; // NOLINT
+ return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT
}
// pd must be already ref'ed.
-static void init(ThreadState *thr, uptr pc, int fd, FdDesc *d) {
- FdDesc **pd = fdaddr(thr, pc, fd);
+static void init(ThreadState *thr, uptr pc, int fd, FdSync *s) {
+ FdDesc *d = fddesc(thr, pc, fd);
// As a matter of fact, we don't intercept all close calls.
// See e.g. libc __res_iclose().
- if (*pd)
- unref(thr, pc, *pd);
- *pd = d;
+ if (d->sync)
+ unref(thr, pc, d->sync);
+ d->sync = s;
+ d->creation_tid = thr->tid;
+ d->creation_stack = CurrentStackId(thr, pc);
// To catch races between fd usage and open.
- MemoryRangeImitateWrite(thr, pc, (uptr)pd, 8);
+ MemoryRangeImitateWrite(thr, pc, (uptr)d, 8);
}
void FdInit() {
- atomic_store(&fdctx.globdesc.rc, (u64)-1, memory_order_relaxed);
- atomic_store(&fdctx.filedesc.rc, (u64)-1, memory_order_relaxed);
- atomic_store(&fdctx.sockdesc.rc, (u64)-1, memory_order_relaxed);
+ atomic_store(&fdctx.globsync.rc, (u64)-1, memory_order_relaxed);
+ atomic_store(&fdctx.filesync.rc, (u64)-1, memory_order_relaxed);
+ atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed);
+}
+
+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);
+ if (tab == 0)
+ break;
+ if (addr >= (uptr)tab && addr < (uptr)(tab + kTableSizeL2)) {
+ int l2 = (addr - (uptr)tab) / sizeof(FdDesc);
+ FdDesc *d = &tab[l2];
+ *fd = l1 * kTableSizeL1 + l2;
+ *tid = d->creation_tid;
+ *stack = d->creation_stack;
+ return true;
+ }
+ }
+ return false;
}
void FdAcquire(ThreadState *thr, uptr pc, int fd) {
- FdDesc **pd = fdaddr(thr, pc, fd);
- FdDesc *d = *pd;
- DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, d);
- MemoryRead8Byte(thr, pc, (uptr)pd);
- if (d)
- Acquire(thr, pc, (uptr)d);
+ FdDesc *d = fddesc(thr, pc, fd);
+ FdSync *s = d->sync;
+ DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
+ MemoryRead8Byte(thr, pc, (uptr)d);
+ if (s)
+ Acquire(thr, pc, (uptr)s);
}
void FdRelease(ThreadState *thr, uptr pc, int fd) {
- FdDesc **pd = fdaddr(thr, pc, fd);
- FdDesc *d = *pd;
- DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, d);
- if (d)
- Release(thr, pc, (uptr)d);
- MemoryRead8Byte(thr, pc, (uptr)pd);
+ FdDesc *d = fddesc(thr, pc, fd);
+ FdSync *s = d->sync;
+ DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
+ if (s)
+ Release(thr, pc, (uptr)s);
+ MemoryRead8Byte(thr, pc, (uptr)d);
}
void FdClose(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
- FdDesc **pd = fdaddr(thr, pc, fd);
+ FdDesc *d = fddesc(thr, pc, fd);
// To catch races between fd usage and close.
- MemoryWrite8Byte(thr, pc, (uptr)pd);
+ MemoryWrite8Byte(thr, pc, (uptr)d);
// We need to clear it, because if we do not intercept any call out there
// that creates fd, we will hit false postives.
- MemoryResetRange(thr, pc, (uptr)pd, 8);
- unref(thr, pc, *pd);
- *pd = 0;
+ MemoryResetRange(thr, pc, (uptr)d, 8);
+ unref(thr, pc, d->sync);
+ d->sync = 0;
+ d->creation_tid = 0;
+ d->creation_stack = 0;
}
void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd);
- init(thr, pc, fd, &fdctx.filedesc);
+ init(thr, pc, fd, &fdctx.filesync);
}
void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
// Ignore the case when user dups not yet connected socket.
- FdDesc **opd = fdaddr(thr, pc, oldfd);
- MemoryRead8Byte(thr, pc, (uptr)opd);
+ FdDesc *od = fddesc(thr, pc, oldfd);
+ MemoryRead8Byte(thr, pc, (uptr)od);
FdClose(thr, pc, newfd);
- init(thr, pc, newfd, ref(*opd));
+ init(thr, pc, newfd, ref(od->sync));
}
void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd);
- FdDesc *d = allocdesc();
- init(thr, pc, rfd, d);
- init(thr, pc, wfd, ref(d));
+ FdSync *s = allocsync();
+ init(thr, pc, rfd, s);
+ init(thr, pc, wfd, ref(s));
}
void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd);
- init(thr, pc, fd, allocdesc());
+ init(thr, pc, fd, allocsync());
}
void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd);
- init(thr, pc, fd, allocdesc());
+ init(thr, pc, fd, allocsync());
}
void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd);
// It can be a UDP socket.
- init(thr, pc, fd, &fdctx.sockdesc);
+ init(thr, pc, fd, &fdctx.socksync);
}
void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd);
// Synchronize connect->accept.
Acquire(thr, pc, (uptr)&fdctx.connectsync);
- init(thr, pc, newfd, &fdctx.sockdesc);
+ init(thr, pc, newfd, &fdctx.socksync);
}
void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) {
@@ -179,7 +206,7 @@
void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd);
- init(thr, pc, fd, &fdctx.sockdesc);
+ init(thr, pc, fd, &fdctx.socksync);
}
uptr File2addr(char *path) {
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_fd.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_fd.h?rev=170417&r1=170416&r2=170417&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_fd.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_fd.h Tue Dec 18 00:57:34 2012
@@ -51,6 +51,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);
uptr File2addr(char *path);
uptr Dir2addr(char *path);
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc?rev=170417&r1=170416&r2=170417&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc Tue Dec 18 00:57:34 2012
@@ -102,6 +102,7 @@
}
static void PrintLocation(const ReportLocation *loc) {
+ char thrbuf[kThreadBufSize];
if (loc->type == ReportLocationGlobal) {
Printf(" Location is global '%s' of size %zu at %zx %s:%d (%s+%p)\n\n",
loc->name, loc->size, loc->addr, loc->file, loc->line,
@@ -112,7 +113,11 @@
loc->size, loc->addr, thread_name(thrbuf, loc->tid));
PrintStack(loc->stack);
} else if (loc->type == ReportLocationStack) {
- Printf(" Location is stack of thread T%d:\n\n", loc->tid);
+ Printf(" Location is stack of %s\n\n", thread_name(thrbuf, loc->tid));
+ } else if (loc->type == ReportLocationFD) {
+ Printf(" Location is file descriptor %d created by %s at:\n",
+ loc->fd, thread_name(thrbuf, loc->tid));
+ PrintStack(loc->stack);
}
}
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_report.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_report.h?rev=170417&r1=170416&r2=170417&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_report.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_report.h Tue Dec 18 00:57:34 2012
@@ -57,7 +57,8 @@
enum ReportLocationType {
ReportLocationGlobal,
ReportLocationHeap,
- ReportLocationStack
+ ReportLocationStack,
+ ReportLocationFD
};
struct ReportLocation {
@@ -67,6 +68,7 @@
char *module;
uptr offset;
int tid;
+ int fd;
char *name;
char *file;
int line;
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=170417&r1=170416&r2=170417&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Tue Dec 18 00:57:34 2012
@@ -23,6 +23,7 @@
#include "tsan_sync.h"
#include "tsan_mman.h"
#include "tsan_flags.h"
+#include "tsan_fd.h"
namespace __tsan {
@@ -227,6 +228,29 @@
if (addr == 0)
return;
#ifndef TSAN_GO
+ int fd = -1;
+ int creat_tid = -1;
+ u32 creat_stack = 0;
+ if (FdLocation(addr, &fd, &creat_tid, &creat_stack)
+ || FdLocation(AlternativeAddress(addr), &fd, &creat_tid, &creat_stack)) {
+ void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
+ ReportLocation *loc = new(mem) ReportLocation();
+ rep_->locs.PushBack(loc);
+ loc->type = ReportLocationFD;
+ loc->fd = fd;
+ loc->tid = creat_tid;
+ uptr ssz = 0;
+ const uptr *stack = StackDepotGet(creat_stack, &ssz);
+ if (stack) {
+ StackTrace trace;
+ trace.Init(stack, ssz);
+ loc->stack = SymbolizeStack(trace);
+ }
+ ThreadContext *tctx = FindThread(creat_tid);
+ if (tctx)
+ AddThread(tctx);
+ return;
+ }
if (allocator()->PointerIsMine((void*)addr)) {
MBlock *b = user_mblock(0, (void*)addr);
ThreadContext *tctx = FindThread(b->alloc_tid);
More information about the llvm-commits
mailing list