aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2013-11-15 16:58:12 +0000
committerDmitry Vyukov <dvyukov@google.com>2013-11-15 16:58:12 +0000
commit11f5309ec1bf13430c8a3a16f177d9e8e1190e38 (patch)
tree21f2f8548e7c6b65aedb1118db1f80c8eccb18c0
parent8975fa7ba8b508ba2d56c75e4f910da78ad3eee4 (diff)
downloadcompiler-rt-11f5309ec1bf13430c8a3a16f177d9e8e1190e38.tar.gz
tsan: add support for robust mutexes
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@194823 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc10
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc3
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h1
-rw-r--r--lib/tsan/lit_tests/mutex_robust.cc36
-rw-r--r--lib/tsan/lit_tests/mutex_robust2.cc41
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc10
-rw-r--r--lib/tsan/rtl/tsan_rtl.h1
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc10
8 files changed, 109 insertions, 3 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index c8ea7187e..d1c897678 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -23,6 +23,7 @@
// COMMON_INTERCEPTOR_ON_EXIT
// COMMON_INTERCEPTOR_MUTEX_LOCK
// COMMON_INTERCEPTOR_MUTEX_UNLOCK
+// COMMON_INTERCEPTOR_MUTEX_REPAIR
// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
@@ -50,6 +51,10 @@
#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
#endif
+#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
+#endif
+
#if SANITIZER_INTERCEPT_STRCMP
static inline int CharCmpX(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
@@ -2179,7 +2184,10 @@ INTERCEPTOR(int, pthread_mutex_lock, void *m) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
int res = REAL(pthread_mutex_lock)(m);
- if (res == 0) COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ if (res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
return res;
}
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index f94e560e9..c1445467c 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -21,6 +21,7 @@
#include <arpa/inet.h>
#include <dirent.h>
+#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <net/if.h>
@@ -762,6 +763,8 @@ namespace __sanitizer {
unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
#endif
+
+ extern const int errno_EOWNERDEAD = EOWNERDEAD;
} // namespace __sanitizer
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 0313af4b7..1e5ae6237 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -921,6 +921,7 @@ namespace __sanitizer {
extern unsigned IOCTL_TIOCSSERIAL;
#endif
+ extern const int errno_EOWNERDEAD;
} // namespace __sanitizer
#define CHECK_TYPE_SIZE(TYPE) \
diff --git a/lib/tsan/lit_tests/mutex_robust.cc b/lib/tsan/lit_tests/mutex_robust.cc
new file mode 100644
index 000000000..b82661607
--- /dev/null
+++ b/lib/tsan/lit_tests/mutex_robust.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+pthread_mutex_t m;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ return 0;
+}
+
+int main() {
+ pthread_mutexattr_t a;
+ pthread_mutexattr_init(&a);
+ pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
+ pthread_mutex_init(&m, &a);
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ sleep(1);
+ if (pthread_mutex_lock(&m) != EOWNERDEAD) {
+ fprintf(stderr, "not EOWNERDEAD\n");
+ exit(1);
+ }
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// This is a correct code, and tsan must not bark.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: EOWNERDEAD
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer
+
diff --git a/lib/tsan/lit_tests/mutex_robust2.cc b/lib/tsan/lit_tests/mutex_robust2.cc
new file mode 100644
index 000000000..5bd7ff682
--- /dev/null
+++ b/lib/tsan/lit_tests/mutex_robust2.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+pthread_mutex_t m;
+int x;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ x = 42;
+ return 0;
+}
+
+int main() {
+ pthread_mutexattr_t a;
+ pthread_mutexattr_init(&a);
+ pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
+ pthread_mutex_init(&m, &a);
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ sleep(1);
+ if (pthread_mutex_trylock(&m) != EOWNERDEAD) {
+ fprintf(stderr, "not EOWNERDEAD\n");
+ exit(1);
+ }
+ x = 43;
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// This is a false positive, tsan must not bark at the data race.
+// But currently it does.
+// CHECK-NOT: WARNING: ThreadSanitizer WARNING: double lock of mutex
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: EOWNERDEAD
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer
+
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 71bfaf346..ef38f7987 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -66,6 +66,7 @@ const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
const int EINVAL = 22;
const int EBUSY = 16;
+const int EOWNERDEAD = 130;
const int EPOLL_CTL_ADD = 1;
const int SIGILL = 4;
const int SIGABRT = 6;
@@ -948,9 +949,10 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
int res = REAL(pthread_mutex_trylock)(m);
- if (res == 0) {
+ if (res == EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ if (res == 0 || res == EOWNERDEAD)
MutexLock(thr, pc, (uptr)m);
- }
return res;
}
@@ -1892,6 +1894,10 @@ struct TsanInterceptorContext {
MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \
+ MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define TSAN_SYSCALL() \
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 4d17f3ae4..4ee667543 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -705,6 +705,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
void Acquire(ThreadState *thr, uptr pc, uptr addr);
void AcquireGlobal(ThreadState *thr, uptr pc);
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index e9eb81acd..409391678 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -224,6 +224,16 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
}
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
+ Context *ctx = CTX();
+ CHECK_GT(thr->in_rtl, 0);
+ DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
+ SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ s->owner_tid = SyncVar::kInvalidTid;
+ s->recursion = 0;
+ s->mtx.Unlock();
+}
+
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);