tsan: better reporting for races on vptr

explicitly say "ctor/dtor vs virtual call"

llvm-svn: 177640
This commit is contained in:
Dmitry Vyukov
2013-03-21 15:37:39 +00:00
parent 2c3b919ad3
commit 0851fa8819
8 changed files with 79 additions and 4 deletions

View 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

View File

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

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

View 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) {

View 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)

View File

@@ -20,6 +20,7 @@ namespace __tsan {
enum ReportType {
ReportTypeRace,
ReportTypeVptrRace,
ReportTypeUseAfterFree,
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,

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

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