From 0851fa881969d5f16540155bd85ce0cd2df95da3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 21 Mar 2013 15:37:39 +0000 Subject: [PATCH] tsan: better reporting for races on vptr explicitly say "ctor/dtor vs virtual call" llvm-svn: 177640 --- .../lib/tsan/lit_tests/vptr_harmful_race.cc | 4 +- .../lib/tsan/lit_tests/vptr_harmful_race2.cc | 51 ++++++++++++++++++++++ compiler-rt/lib/tsan/rtl/tsan_interface.h | 1 + compiler-rt/lib/tsan/rtl/tsan_interface_inl.h | 16 ++++++- compiler-rt/lib/tsan/rtl/tsan_report.cc | 2 + compiler-rt/lib/tsan/rtl/tsan_report.h | 1 + compiler-rt/lib/tsan/rtl/tsan_rtl.h | 1 + compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc | 7 ++- 8 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/lib/tsan/lit_tests/vptr_harmful_race2.cc diff --git a/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race.cc b/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race.cc index f51ba7e..76d31c0 100644 --- a/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race.cc +++ b/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race.cc @@ -2,6 +2,7 @@ #include #include #include +#include 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 index 0000000..4bcf1a4 --- /dev/null +++ b/compiler-rt/lib/tsan/lit_tests/vptr_harmful_race2.cc @@ -0,0 +1,51 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include +#include +#include +#include + +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 diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface.h b/compiler-rt/lib/tsan/rtl/tsan_interface.h index 28eea14..2452661 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interface.h @@ -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; diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h b/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h index 29e2b21..0187e49 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_inl.h @@ -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) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc index b394c40..30e5488 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc @@ -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) diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.h b/compiler-rt/lib/tsan/rtl/tsan_report.h index b2b7b53..eacb10c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.h +++ b/compiler-rt/lib/tsan/rtl/tsan_report.h @@ -20,6 +20,7 @@ namespace __tsan { enum ReportType { ReportTypeRace, + ReportTypeVptrRace, ReportTypeUseAfterFree, ReportTypeThreadLeak, ReportTypeMutexDestroyLocked, diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index e57fcc7..c216a80 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -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; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc index 18ab18e..50c5311 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc @@ -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); -- 2.7.4