tsan: better reporting for races on vptr
authorDmitry Vyukov <dvyukov@google.com>
Thu, 21 Mar 2013 15:37:39 +0000 (15:37 +0000)
committerDmitry Vyukov <dvyukov@google.com>
Thu, 21 Mar 2013 15:37:39 +0000 (15:37 +0000)
explicitly say "ctor/dtor vs virtual call"

llvm-svn: 177640

compiler-rt/lib/tsan/lit_tests/vptr_harmful_race.cc
compiler-rt/lib/tsan/lit_tests/vptr_harmful_race2.cc [new file with mode: 0644]
compiler-rt/lib/tsan/rtl/tsan_interface.h
compiler-rt/lib/tsan/rtl/tsan_interface_inl.h
compiler-rt/lib/tsan/rtl/tsan_report.cc
compiler-rt/lib/tsan/rtl/tsan_report.h
compiler-rt/lib/tsan/rtl/tsan_rtl.h
compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc

index f51ba7e..76d31c0 100644 (file)
@@ -2,6 +2,7 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <stdio.h>
+#include <unistd.h>
 
 struct A {
   A() {
@@ -34,6 +35,7 @@ void *Thread1(void *x) {
 }
 
 void *Thread2(void *x) {
+  sleep(1);
   delete obj;
   return NULL;
 }
@@ -46,4 +48,4 @@ int main() {
   pthread_join(t[1], NULL);
 }
 
-// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race2.cc b/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race2.cc
new file mode 100644 (file)
index 0000000..4bcf1a4
--- /dev/null
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+  A() {
+    sem_init(&sem_, 0, 0);
+  }
+  virtual void F() {
+  }
+  void Done() {
+    sem_post(&sem_);
+  }
+  virtual ~A() {
+    sem_wait(&sem_);
+    sem_destroy(&sem_);
+  }
+  sem_t sem_;
+};
+
+struct B : A {
+  virtual void F() {
+  }
+  virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+  sleep(1);
+  obj->F();
+  obj->Done();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  delete obj;
+  return NULL;
+}
+
+int main() {
+  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
index 28eea14..2452661 100644 (file)
@@ -41,6 +41,7 @@ void __tsan_write4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_write8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_write16(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 
+void __tsan_vptr_read(void **vptr_p) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_vptr_update(void **vptr_p, void *new_val)
     SANITIZER_INTERFACE_ATTRIBUTE;
 
index 29e2b21..0187e49 100644 (file)
@@ -52,8 +52,20 @@ void __tsan_write8(void *addr) {
 
 void __tsan_vptr_update(void **vptr_p, void *new_val) {
   CHECK_EQ(sizeof(vptr_p), 8);
-  if (*vptr_p != new_val)
-    MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
+  if (*vptr_p != new_val) {
+    ThreadState *thr = cur_thread();
+    thr->is_vptr_access = true;
+    MemoryWrite(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+    thr->is_vptr_access = false;
+  }
+}
+
+void __tsan_vptr_read(void **vptr_p) {
+  CHECK_EQ(sizeof(vptr_p), 8);
+  ThreadState *thr = cur_thread();
+  thr->is_vptr_access = true;
+  MemoryRead(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+  thr->is_vptr_access = false;
 }
 
 void __tsan_func_entry(void *pc) {
index b394c40..30e5488 100644 (file)
@@ -46,6 +46,8 @@ const char *thread_name(char *buf, int tid) {
 static const char *ReportTypeString(ReportType typ) {
   if (typ == ReportTypeRace)
     return "data race";
+  if (typ == ReportTypeVptrRace)
+    return "data race on vptr (ctor/dtor vs virtual call)";
   if (typ == ReportTypeUseAfterFree)
     return "heap-use-after-free";
   if (typ == ReportTypeThreadLeak)
index b2b7b53..eacb10c 100644 (file)
@@ -20,6 +20,7 @@ namespace __tsan {
 
 enum ReportType {
   ReportTypeRace,
+  ReportTypeVptrRace,
   ReportTypeUseAfterFree,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
index e57fcc7..c216a80 100644 (file)
@@ -426,6 +426,7 @@ struct ThreadState {
   bool in_symbolizer;
   bool is_alive;
   bool is_freeing;
+  bool is_vptr_access;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
index 18ab18e..50c5311 100644 (file)
@@ -616,7 +616,12 @@ void ReportRace(ThreadState *thr) {
   Context *ctx = CTX();
   ThreadRegistryLock l0(ctx->thread_registry);
 
-  ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
+  ReportType typ = ReportTypeRace;
+  if (thr->is_vptr_access)
+    typ = ReportTypeVptrRace;
+  else if (freed)
+    typ = ReportTypeUseAfterFree;
+  ScopedReport rep(typ);
   const uptr kMop = 2;
   StackTrace traces[kMop];
   const uptr toppc = TraceTopPC(thr);