[llvm-commits] [compiler-rt] r169970 - in /compiler-rt/trunk/lib/tsan: lit_tests/fd_dup_norace.cc rtl/tsan_interceptors.cc rtl/tsan_mman.h rtl/tsan_stat.cc rtl/tsan_stat.h

Dmitry Vyukov dvyukov at google.com
Wed Dec 12 03:59:31 PST 2012


Author: dvyukov
Date: Wed Dec 12 05:59:30 2012
New Revision: 169970

URL: http://llvm.org/viewvc/llvm-project?rev=169970&view=rev
Log:
tsan: more precise handling of IO synchronization

Added:
    compiler-rt/trunk/lib/tsan/lit_tests/fd_dup_norace.cc
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h

Added: compiler-rt/trunk/lib/tsan/lit_tests/fd_dup_norace.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/fd_dup_norace.cc?rev=169970&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/fd_dup_norace.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/fd_dup_norace.cc Wed Dec 12 05:59:30 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>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+  char buf;
+  read(fds[0], &buf, 1);
+  close(fds[0]);
+  return 0;
+}
+
+void *Thread2(void *x) {
+  close(fds[1]);
+  return 0;
+}
+
+int main() {
+  fds[0] = open("/dev/random", O_RDONLY);
+  fds[1] = dup2(fds[0], 100);
+  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-NOT: WARNING: ThreadSanitizer: data race

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=169970&r1=169969&r2=169970&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Dec 12 05:59:30 2012
@@ -22,6 +22,7 @@
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
+#include "tsan_fd.h"
 
 using namespace __tsan;  // NOLINT
 
@@ -54,6 +55,7 @@
 extern "C" void _exit(int status);
 extern "C" int __cxa_atexit(void (*func)(void *arg), void *arg, void *dso);
 extern "C" int *__errno_location();
+extern "C" int fileno(void *stream);
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
 const int kPthreadAttrSize = 56;
@@ -128,10 +130,8 @@
   SignalContext *ctx = (SignalContext*)thr->signal_ctx;
   if (ctx == 0 && thr->is_alive) {
     ScopedInRtl in_rtl;
-    ctx = (SignalContext*)internal_alloc(
-        MBlockSignal, sizeof(*ctx));
-    MemoryResetRange(thr, 0, (uptr)ctx, sizeof(*ctx));
-    internal_memset(ctx, 0, sizeof(*ctx));
+    ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
+    MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
     thr->signal_ctx = ctx;
   }
   return ctx;
@@ -310,216 +310,6 @@
   Die();
 }
 
-enum FdType {
-  FdGlobal,  // Something we don't know about, global sync.
-  FdNone,  // Does not require any sync.
-  FdFile,
-  FdSock,
-  FdPipe,
-  FdEvent,  // see eventfd()
-  FdPoll
-};
-
-struct FdDesc {
-  FdType type;
-  u64 sync;
-};
-
-struct FdContext {
-  static const int kMaxFds = 10 * 1024;  // Everything else is synced globally.
-  FdDesc desc[kMaxFds];
-  // Addresses used for synchronization.
-  u64 fdglobal;
-  u64 fdfile;
-  u64 fdsock;
-  u64 fdpipe;
-  u64 fdpoll;
-  u64 fdevent;
-};
-
-static FdContext fdctx;
-
-static void FdInit() {
-  fdctx.desc[0].type = FdNone;
-  fdctx.desc[1].type = FdNone;
-  fdctx.desc[2].type = FdNone;
-}
-
-static void *FdAddr(int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return &fdctx.fdglobal;
-  FdDesc *desc = &fdctx.desc[fd];
-  if (desc->type == FdNone)
-    return 0;
-  if (desc->type == FdGlobal)
-    return &fdctx.fdglobal;
-  if (desc->type == FdFile)
-    return &fdctx.fdfile;
-  if (desc->type == FdSock)
-    return &fdctx.fdsock;
-  if (desc->type == FdPipe)
-    return &fdctx.fdpipe;
-  if (desc->type == FdEvent)
-    return &fdctx.fdevent;
-  if (desc->type == FdPoll)
-    return &fdctx.fdpoll;
-  CHECK(0);
-  return 0;
-}
-
-static void FdAcquire(ThreadState *thr, uptr pc, int fd) {
-  void *addr = FdAddr(fd);
-  DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, addr);
-  if (addr)
-    Acquire(thr, pc, (uptr)addr);
-  if (fd < FdContext::kMaxFds)
-    MemoryRead8Byte(thr, pc, (uptr)&fdctx.desc[fd].sync);
-}
-
-static void FdRelease(ThreadState *thr, uptr pc, int fd) {
-  void *addr = FdAddr(fd);
-  DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, addr);
-  if (addr)
-    Release(thr, pc, (uptr)addr);
-  if (fd < FdContext::kMaxFds)
-    MemoryRead8Byte(thr, pc, (uptr)&fdctx.desc[fd].sync);
-}
-
-static void FdClose(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  SyncVar *s = CTX()->synctab.GetAndRemove(thr, pc, (uptr)&desc->sync);
-  if (s)
-    DestroyAndFree(s);
-  // FIXME(dvyukov): change to FdNone once we handle all fd operations.
-  desc->type = FdGlobal;
-  // To catch races between fd usage and close.
-  MemoryWrite8Byte(thr, pc, (uptr)&desc->sync);
-  // 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)&desc->sync, sizeof(desc->sync));
-}
-
-static void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  desc->type = FdFile;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&desc->sync, sizeof(desc->sync));
-}
-
-static void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
-  if (oldfd >= FdContext::kMaxFds || newfd >= FdContext::kMaxFds) {
-    if (oldfd < FdContext::kMaxFds) {
-      // FIXME(dvyukov): here we lose old sync object associated with the fd,
-      // this can lead to false positives.
-      FdDesc *odesc = &fdctx.desc[oldfd];
-      odesc->type = FdGlobal;
-    }
-    if (newfd < FdContext::kMaxFds) {
-      FdClose(thr, pc, newfd);
-      FdDesc *ndesc = &fdctx.desc[newfd];
-      ndesc->type = FdGlobal;
-    }
-    return;
-  }
-
-  FdClose(thr, pc, newfd);
-  FdDesc *ndesc = &fdctx.desc[newfd];
-  ndesc->type = FdFile;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&ndesc->sync, sizeof(ndesc->sync));
-}
-
-static void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
-  if (rfd >= FdContext::kMaxFds || wfd >= FdContext::kMaxFds) {
-    if (rfd < FdContext::kMaxFds) {
-      FdDesc *rdesc = &fdctx.desc[rfd];
-      rdesc->type = FdGlobal;
-    }
-    if (wfd < FdContext::kMaxFds) {
-      FdDesc *wdesc = &fdctx.desc[wfd];
-      wdesc->type = FdGlobal;
-    }
-    return;
-  }
-
-  FdDesc *rdesc = &fdctx.desc[rfd];
-  rdesc->type = FdPipe;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&rdesc->sync, sizeof(rdesc->sync));
-
-  FdDesc *wdesc = &fdctx.desc[wfd];
-  wdesc->type = FdPipe;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&wdesc->sync, sizeof(rdesc->sync));
-
-  DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd);
-}
-
-static void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  desc->type = FdEvent;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&desc->sync, sizeof(desc->sync));
-}
-
-static void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  desc->type = FdPoll;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&desc->sync, sizeof(desc->sync));
-}
-
-static void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  // It can be UDP socket, let's assume they are not used for synchronization.
-  desc->type = FdNone;
-  // To catch races between fd usage and open.
-  MemoryRangeImitateWrite(thr, pc, (uptr)&desc->sync, sizeof(desc->sync));
-}
-
-static void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
-  if (fd < FdContext::kMaxFds) {
-    FdDesc *desc = &fdctx.desc[fd];
-    desc->type = FdNone;
-    MemoryRead8Byte(thr, pc, (uptr)&desc->sync);
-  }
-  if (newfd < FdContext::kMaxFds) {
-    FdDesc *desc = &fdctx.desc[newfd];
-    desc->type = FdSock;
-    MemoryWrite8Byte(thr, pc, (uptr)&desc->sync);
-  }
-}
-
-static void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
-  if (fd >= FdContext::kMaxFds)
-    return;
-  FdDesc *desc = &fdctx.desc[fd];
-  desc->type = FdSock;
-  MemoryWrite8Byte(thr, pc, (uptr)&desc->sync);
-}
-
-static uptr file2addr(char *path) {
-  (void)path;
-  static u64 addr;
-  return (uptr)&addr;
-}
-
-static uptr dir2addr(char *path) {
-  (void)path;
-  static u64 addr;
-  return (uptr)&addr;
-}
-
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
   void *p = 0;
   {
@@ -850,7 +640,7 @@
     SignalContext *sctx = thr->signal_ctx;
     if (sctx) {
       thr->signal_ctx = 0;
-      internal_free(sctx);
+      UnmapOrDie(sctx, sizeof(*sctx));
     }
   }
 }
@@ -1124,11 +914,13 @@
   return res;
 }
 
+/*
 TSAN_INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, c, a);
   int res = REAL(pthread_cond_init)(c, a);
   return res;
 }
+*/
 
 TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) {
   SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, c);
@@ -1278,6 +1070,14 @@
   return fd;
 }
 
+TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
+  SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
+  int fd = REAL(open64)(name, flags, mode);
+  if (fd >= 0)
+    FdFileCreate(thr, pc, fd);
+  return fd;
+}
+
 TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
   int fd = REAL(creat)(name, mode);
@@ -1286,6 +1086,14 @@
   return fd;
 }
 
+TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
+  SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
+  int fd = REAL(creat64)(name, mode);
+  if (fd >= 0)
+    FdFileCreate(thr, pc, fd);
+  return fd;
+}
+
 TSAN_INTERCEPTOR(int, dup, int oldfd) {
   SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
   int newfd = REAL(dup)(oldfd);
@@ -1368,10 +1176,18 @@
 
 TSAN_INTERCEPTOR(int, close, int fd) {
   SCOPED_TSAN_INTERCEPTOR(close, fd);
-  FdClose(thr, pc, fd);
+  if (fd >= 0)
+    FdClose(thr, pc, fd);
   return REAL(close)(fd);
 }
 
+TSAN_INTERCEPTOR(int, __close, int fd) {
+  SCOPED_TSAN_INTERCEPTOR(__close, fd);
+  if (fd >= 0)
+    FdClose(thr, pc, fd);
+  return REAL(__close)(fd);
+}
+
 TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
   int res = REAL(pipe)(pipefd);
@@ -1502,7 +1318,7 @@
 
 TSAN_INTERCEPTOR(int, unlink, char *path) {
   SCOPED_TSAN_INTERCEPTOR(unlink, path);
-  Release(thr, pc, file2addr(path));
+  Release(thr, pc, File2addr(path));
   int res = REAL(unlink)(path);
   return res;
 }
@@ -1510,7 +1326,40 @@
 TSAN_INTERCEPTOR(void*, fopen, char *path, char *mode) {
   SCOPED_TSAN_INTERCEPTOR(fopen, path, mode);
   void *res = REAL(fopen)(path, mode);
-  Acquire(thr, pc, file2addr(path));
+  Acquire(thr, pc, File2addr(path));
+  if (res) {
+    int fd = fileno(res);
+    if (fd >= 0)
+      FdFileCreate(thr, pc, fd);
+  }
+  return res;
+}
+
+TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) {
+  SCOPED_TSAN_INTERCEPTOR(freopen, path, mode, stream);
+  if (stream) {
+    int fd = fileno(stream);
+    if (fd >= 0)
+      FdClose(thr, pc, fd);
+  }
+  void *res = REAL(freopen)(path, mode, stream);
+  Acquire(thr, pc, File2addr(path));
+  if (res) {
+    int fd = fileno(res);
+    if (fd >= 0)
+      FdFileCreate(thr, pc, fd);
+  }
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, fclose, void *stream) {
+  SCOPED_TSAN_INTERCEPTOR(fclose, stream);
+  if (stream) {
+    int fd = fileno(stream);
+    if (fd >= 0)
+      FdClose(thr, pc, fd);
+  }
+  int res = REAL(fclose)(stream);
   return res;
 }
 
@@ -1534,7 +1383,7 @@
 
 TSAN_INTERCEPTOR(int, rmdir, char *path) {
   SCOPED_TSAN_INTERCEPTOR(rmdir, path);
-  Release(thr, pc, dir2addr(path));
+  Release(thr, pc, Dir2addr(path));
   int res = REAL(rmdir)(path);
   return res;
 }
@@ -1542,7 +1391,8 @@
 TSAN_INTERCEPTOR(void*, opendir, char *path) {
   SCOPED_TSAN_INTERCEPTOR(opendir, path);
   void *res = REAL(opendir)(path);
-  Acquire(thr, pc, dir2addr(path));
+  if (res != 0)
+    Acquire(thr, pc, Dir2addr(path));
   return res;
 }
 
@@ -1853,7 +1703,7 @@
   TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
   TSAN_INTERCEPT(pthread_rwlock_unlock);
 
-  TSAN_INTERCEPT(pthread_cond_init);
+  // TSAN_INTERCEPT(pthread_cond_init);
   TSAN_INTERCEPT(pthread_cond_destroy);
   TSAN_INTERCEPT(pthread_cond_signal);
   TSAN_INTERCEPT(pthread_cond_broadcast);
@@ -1875,7 +1725,9 @@
   TSAN_INTERCEPT(sem_getvalue);
 
   TSAN_INTERCEPT(open);
+  TSAN_INTERCEPT(open64);
   TSAN_INTERCEPT(creat);
+  TSAN_INTERCEPT(creat64);
   TSAN_INTERCEPT(dup);
   TSAN_INTERCEPT(dup2);
   TSAN_INTERCEPT(dup3);
@@ -1907,6 +1759,8 @@
 
   TSAN_INTERCEPT(unlink);
   TSAN_INTERCEPT(fopen);
+  TSAN_INTERCEPT(freopen);
+  TSAN_INTERCEPT(fclose);
   TSAN_INTERCEPT(fread);
   TSAN_INTERCEPT(fwrite);
   TSAN_INTERCEPT(puts);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h?rev=169970&r1=169969&r2=169970&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h Wed Dec 12 05:59:30 2012
@@ -59,6 +59,7 @@
   MBlockSuppression,
   MBlockExpectRace,
   MBlockSignal,
+  MBlockFD,
 
   // This must be the last.
   MBlockTypeCount

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc?rev=169970&r1=169969&r2=169970&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc Wed Dec 12 05:59:30 2012
@@ -182,7 +182,9 @@
   name[StatInt_sem_post]                 = "  sem_post                        ";
   name[StatInt_sem_getvalue]             = "  sem_getvalue                    ";
   name[StatInt_open]                     = "  open                            ";
+  name[StatInt_open64]                   = "  open64                          ";
   name[StatInt_creat]                    = "  creat                           ";
+  name[StatInt_creat64]                  = "  creat64                         ";
   name[StatInt_dup]                      = "  dup                             ";
   name[StatInt_dup2]                     = "  dup2                            ";
   name[StatInt_dup3]                     = "  dup3                            ";
@@ -194,6 +196,7 @@
   name[StatInt_epoll_create]             = "  epoll_create                    ";
   name[StatInt_epoll_create1]            = "  epoll_create1                   ";
   name[StatInt_close]                    = "  close                           ";
+  name[StatInt___close]                  = "  __close                         ";
   name[StatInt_pipe]                     = "  pipe                            ";
   name[StatInt_pipe2]                    = "  pipe2                           ";
   name[StatInt_read]                     = "  read                            ";
@@ -212,6 +215,8 @@
   name[StatInt_recvmsg]                  = "  recvmsg                         ";
   name[StatInt_unlink]                   = "  unlink                          ";
   name[StatInt_fopen]                    = "  fopen                           ";
+  name[StatInt_freopen]                  = "  freopen                         ";
+  name[StatInt_fclose]                   = "  fclose                          ";
   name[StatInt_fread]                    = "  fread                           ";
   name[StatInt_fwrite]                   = "  fwrite                          ";
   name[StatInt_puts]                     = "  puts                            ";

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h?rev=169970&r1=169969&r2=169970&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h Wed Dec 12 05:59:30 2012
@@ -177,7 +177,9 @@
   StatInt_sem_post,
   StatInt_sem_getvalue,
   StatInt_open,
+  StatInt_open64,
   StatInt_creat,
+  StatInt_creat64,
   StatInt_dup,
   StatInt_dup2,
   StatInt_dup3,
@@ -189,6 +191,7 @@
   StatInt_epoll_create,
   StatInt_epoll_create1,
   StatInt_close,
+  StatInt___close,
   StatInt_pipe,
   StatInt_pipe2,
   StatInt_read,
@@ -207,6 +210,8 @@
   StatInt_recvmsg,
   StatInt_unlink,
   StatInt_fopen,
+  StatInt_freopen,
+  StatInt_fclose,
   StatInt_fread,
   StatInt_fwrite,
   StatInt_puts,





More information about the llvm-commits mailing list