From 11f5309ec1bf13430c8a3a16f177d9e8e1190e38 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 15 Nov 2013 16:58:12 +0000 Subject: tsan: add support for robust mutexes git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@194823 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 10 +++++- .../sanitizer_platform_limits_posix.cc | 3 ++ .../sanitizer_platform_limits_posix.h | 1 + lib/tsan/lit_tests/mutex_robust.cc | 36 +++++++++++++++++++ lib/tsan/lit_tests/mutex_robust2.cc | 41 ++++++++++++++++++++++ lib/tsan/rtl/tsan_interceptors.cc | 10 ++++-- lib/tsan/rtl/tsan_rtl.h | 1 + lib/tsan/rtl/tsan_rtl_mutex.cc | 10 ++++++ 8 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 lib/tsan/lit_tests/mutex_robust.cc create mode 100644 lib/tsan/lit_tests/mutex_robust2.cc 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 #include +#include #include #include #include @@ -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 +#include +#include +#include +#include + +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 +#include +#include +#include +#include + +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); -- cgit v1.2.3