diff options
author | Kuba Brecka <kuba.brecka@gmail.com> | 2016-03-16 15:39:20 +0000 |
---|---|---|
committer | Kuba Brecka <kuba.brecka@gmail.com> | 2016-03-16 15:39:20 +0000 |
commit | cf3edeb92e31d2c4bcc7575c1eb2c7abd8c5b15a (patch) | |
tree | df7d2ea1822c948fca1bed88077d10fe78724b44 | |
parent | 0813bfea15cfb9fd2da85f7a28123a090dcc65a7 (diff) |
[tsan] Detect uses of uninitialized, destroyed and invalid mutexes
This patch adds a new TSan report type, ReportTypeMutexInvalidAccess, which is triggered when pthread_mutex_lock or pthread_mutex_unlock returns EINVAL (this means the mutex is invalid, uninitialized or already destroyed).
Differential Revision: http://reviews.llvm.org/D18132
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@263641 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 11 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_debugging.cc | 1 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_report.cc | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_report.h | 1 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl.h | 1 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl_mutex.cc | 8 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_suppressions.cc | 2 | ||||
-rw-r--r-- | test/tsan/mutex_lock_destroyed.cc | 25 |
9 files changed, 54 insertions, 1 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 560dd3e11..7571d005c 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -91,6 +91,10 @@ #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {} #endif +#ifndef COMMON_INTERCEPTOR_MUTEX_INVALID +#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) {} +#endif + #ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg)) #endif @@ -3346,6 +3350,8 @@ INTERCEPTOR(int, pthread_mutex_lock, void *m) { COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); if (res == 0 || res == errno_EOWNERDEAD) COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); return res; } @@ -3353,7 +3359,10 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m); COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); - return REAL(pthread_mutex_unlock)(m); + int res = REAL(pthread_mutex_unlock)(m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; } #define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock) diff --git a/lib/tsan/rtl/tsan_debugging.cc b/lib/tsan/rtl/tsan_debugging.cc index c43f78380..16d52a979 100644 --- a/lib/tsan/rtl/tsan_debugging.cc +++ b/lib/tsan/rtl/tsan_debugging.cc @@ -25,6 +25,7 @@ static const char *ReportTypeDescription(ReportType typ) { if (typ == ReportTypeThreadLeak) return "thread-leak"; if (typ == ReportTypeMutexDestroyLocked) return "locked-mutex-destroy"; if (typ == ReportTypeMutexDoubleLock) return "mutex-double-lock"; + if (typ == ReportTypeMutexInvalidAccess) return "mutex-invalid-access"; if (typ == ReportTypeMutexBadUnlock) return "mutex-bad-unlock"; if (typ == ReportTypeMutexBadReadLock) return "mutex-bad-read-lock"; if (typ == ReportTypeMutexBadReadUnlock) return "mutex-bad-read-unlock"; diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 3b7361f13..029fe5c62 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -2409,6 +2409,10 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) +#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \ + MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + #if !SANITIZER_MAC #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 1b7a62ca2..5c018c8f7 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -96,6 +96,8 @@ static const char *ReportTypeString(ReportType typ) { return "destroy of a locked mutex"; if (typ == ReportTypeMutexDoubleLock) return "double lock of a mutex"; + if (typ == ReportTypeMutexInvalidAccess) + return "use of an invalid mutex (e.g. uninitialized or destroyed)"; if (typ == ReportTypeMutexBadUnlock) return "unlock of an unlocked mutex (or by a wrong thread)"; if (typ == ReportTypeMutexBadReadLock) diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h index 3e344a048..bcdd72c4f 100644 --- a/lib/tsan/rtl/tsan_report.h +++ b/lib/tsan/rtl/tsan_report.h @@ -27,6 +27,7 @@ enum ReportType { ReportTypeThreadLeak, ReportTypeMutexDestroyLocked, ReportTypeMutexDoubleLock, + ReportTypeMutexInvalidAccess, ReportTypeMutexBadUnlock, ReportTypeMutexBadReadLock, ReportTypeMutexBadReadUnlock, diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 9b9f29a1e..057a3a6b7 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -695,6 +695,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false); 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 MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr); void Acquire(ThreadState *thr, uptr pc, uptr addr); // AcquireGlobal synchronizes the current thread with all other threads. diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index 62ab7aa6b..c5682873a 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -350,6 +350,14 @@ void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { s->mtx.Unlock(); } +void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) { + DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); + u64 mid = s->GetId(); + s->mtx.Unlock(); + ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, mid); +} + void Acquire(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: Acquire %zx\n", thr->tid, addr); if (thr->ignore_sync) diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc index 64a5a6672..aea3cb978 100644 --- a/lib/tsan/rtl/tsan_suppressions.cc +++ b/lib/tsan/rtl/tsan_suppressions.cc @@ -80,6 +80,8 @@ static const char *conv(ReportType typ) { return kSuppressionMutex; else if (typ == ReportTypeMutexDoubleLock) return kSuppressionMutex; + else if (typ == ReportTypeMutexInvalidAccess) + return kSuppressionMutex; else if (typ == ReportTypeMutexBadUnlock) return kSuppressionMutex; else if (typ == ReportTypeMutexBadReadLock) diff --git a/test/tsan/mutex_lock_destroyed.cc b/test/tsan/mutex_lock_destroyed.cc new file mode 100644 index 000000000..52d6be621 --- /dev/null +++ b/test/tsan/mutex_lock_destroyed.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %deflake %run %t | FileCheck %s +// RUN: %deflake %run %t 1 | FileCheck %s + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { + pthread_mutex_t *m = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(m, 0); + pthread_mutex_lock(m); + pthread_mutex_unlock(m); + pthread_mutex_destroy(m); + + if (argc > 1 && argv[1][0] == '1') + free(m); + + pthread_mutex_lock(m); + // CHECK: WARNING: ThreadSanitizer: use of an invalid mutex (e.g. uninitialized or destroyed) + // CHECK: #0 pthread_mutex_lock + // CHECK: #1 main {{.*}}mutex_lock_destroyed.cc:[[@LINE-3]] + + return 0; +} |