diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2013-09-02 18:06:28 +0000 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2013-09-02 18:06:28 +0000 |
commit | f061554e8bbfad5e29dcd9e81feb725b75869fa0 (patch) | |
tree | e23929748f3bad3a55170207fb75ff71940d07a6 | |
parent | b6c3c12e3009bb2fe384dc156a97afb51767399c (diff) |
tsan: properly intercept pthread_cond functions
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@189767 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/interception/interception_linux.cc | 6 | ||||
-rw-r--r-- | lib/interception/interception_linux.h | 6 | ||||
-rw-r--r-- | lib/tsan/lit_tests/cond_version.c | 44 | ||||
-rwxr-xr-x | lib/tsan/lit_tests/test_output.sh | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 59 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_stat.cc | 15 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_stat.h | 12 |
7 files changed, 102 insertions, 42 deletions
diff --git a/lib/interception/interception_linux.cc b/lib/interception/interception_linux.cc index 009098fbd..67caca32c 100644 --- a/lib/interception/interception_linux.cc +++ b/lib/interception/interception_linux.cc @@ -15,7 +15,6 @@ #ifdef __linux__ #include "interception.h" -#include <stddef.h> // for NULL #include <dlfcn.h> // for dlsym namespace __interception { @@ -24,6 +23,11 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, *func_addr = (uptr)dlsym(RTLD_NEXT, func_name); return real == wrapper; } + +void *GetFuncAddrVer(const char *func_name, const char *ver) { + return dlvsym(RTLD_NEXT, func_name, ver); +} + } // namespace __interception diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h index dba60bf73..200a9ae7d 100644 --- a/lib/interception/interception_linux.h +++ b/lib/interception/interception_linux.h @@ -25,6 +25,7 @@ namespace __interception { // returns true if a function with the given name was found. bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, uptr real, uptr wrapper); +void *GetFuncAddrVer(const char *func_name, const char *ver); } // namespace __interception #define INTERCEPT_FUNCTION_LINUX(func) \ @@ -33,5 +34,10 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, (::__interception::uptr)&(func), \ (::__interception::uptr)&WRAP(func)) +#define INTERCEPT_FUNCTION_VER(func, funcver, symver) \ + __asm__(".symver "#funcver","#func"@"#symver); \ + ::__interception::real_##funcver = (funcver##_f)(unsigned long) \ + ::__interception::GetFuncAddrVer(#func, #symver) + #endif // INTERCEPTION_LINUX_H #endif // __linux__ diff --git a/lib/tsan/lit_tests/cond_version.c b/lib/tsan/lit_tests/cond_version.c new file mode 100644 index 000000000..1f966bfac --- /dev/null +++ b/lib/tsan/lit_tests/cond_version.c @@ -0,0 +1,44 @@ +// RUN: %clang_tsan -O1 %s -o %t -lrt && %t 2>&1 | FileCheck %s +// Test that pthread_cond is properly intercepted, +// previously there were issues with versioned symbols. +// CHECK: OK + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <time.h> +#include <errno.h> + +int main() { + typedef unsigned long long u64; + pthread_mutex_t m; + pthread_cond_t c; + pthread_condattr_t at; + struct timespec ts0, ts1, ts2; + int res; + u64 sleep; + + pthread_mutex_init(&m, 0); + pthread_condattr_init(&at); + pthread_condattr_setclock(&at, CLOCK_MONOTONIC); + pthread_cond_init(&c, &at); + + clock_gettime(CLOCK_MONOTONIC, &ts0); + ts1 = ts0; + ts1.tv_sec += 2; + + pthread_mutex_lock(&m); + do { + res = pthread_cond_timedwait(&c, &m, &ts1); + } while (res == 0); + pthread_mutex_unlock(&m); + + clock_gettime(CLOCK_MONOTONIC, &ts2); + sleep = (u64)ts2.tv_sec * 1000000000 + ts2.tv_nsec - + ((u64)ts0.tv_sec * 1000000000 + ts0.tv_nsec); + if (res != ETIMEDOUT) + exit(printf("bad return value %d, want %d\n", res, ETIMEDOUT)); + if (sleep < 1000000000) + exit(printf("bad sleep duration %lluns, want %dns\n", sleep, 1000000000)); + fprintf(stderr, "OK\n"); +} diff --git a/lib/tsan/lit_tests/test_output.sh b/lib/tsan/lit_tests/test_output.sh index 94b742a97..f1f1e4bcd 100755 --- a/lib/tsan/lit_tests/test_output.sh +++ b/lib/tsan/lit_tests/test_output.sh @@ -13,7 +13,7 @@ BLACKLIST=$ROOTDIR/lit_tests/Helpers/blacklist.txt # TODO: add testing for all of -O0...-O3 CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -Wall" -LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a" +LDFLAGS="-pie -lpthread -ldl -lrt $ROOTDIR/rtl/libtsan.a" test_file() { SRC=$1 diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 9d6d3e030..6dd1d860e 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -1051,46 +1051,43 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) { return res; } -// libpthread.so contains several versions of pthread_cond_init symbol. -// When we just dlsym() it, we get the wrong (old) version. -/* -TSAN_INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, c, a); - int res = REAL(pthread_cond_init)(c, a); +TSAN_INTERCEPTOR(int, pthread_cond_init_2_3_2, void *c, void *a) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_init_2_3_2, c, a); + int res = REAL(pthread_cond_init_2_3_2)(c, a); return res; } -*/ -TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, c); - int res = REAL(pthread_cond_destroy)(c); +TSAN_INTERCEPTOR(int, pthread_cond_destroy_2_3_2, void *c) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy_2_3_2, c); + int res = REAL(pthread_cond_destroy_2_3_2)(c); return res; } -TSAN_INTERCEPTOR(int, pthread_cond_signal, void *c) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, c); - int res = REAL(pthread_cond_signal)(c); +TSAN_INTERCEPTOR(int, pthread_cond_signal_2_3_2, void *c) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal_2_3_2, c); + int res = REAL(pthread_cond_signal_2_3_2)(c); return res; } -TSAN_INTERCEPTOR(int, pthread_cond_broadcast, void *c) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, c); - int res = REAL(pthread_cond_broadcast)(c); +TSAN_INTERCEPTOR(int, pthread_cond_broadcast_2_3_2, void *c) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast_2_3_2, c); + int res = REAL(pthread_cond_broadcast_2_3_2)(c); return res; } -TSAN_INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, c, m); +TSAN_INTERCEPTOR(int, pthread_cond_wait_2_3_2, void *c, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait_2_3_2, c, m); MutexUnlock(thr, pc, (uptr)m); - int res = REAL(pthread_cond_wait)(c, m); + int res = REAL(pthread_cond_wait_2_3_2)(c, m); MutexLock(thr, pc, (uptr)m); return res; } -TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, c, m, abstime); +TSAN_INTERCEPTOR(int, pthread_cond_timedwait_2_3_2, void *c, void *m, + void *abstime) { + SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_2_3_2, c, m, abstime); MutexUnlock(thr, pc, (uptr)m); - int res = REAL(pthread_cond_timedwait)(c, m, abstime); + int res = REAL(pthread_cond_timedwait_2_3_2)(c, m, abstime); MutexLock(thr, pc, (uptr)m); return res; } @@ -1984,12 +1981,18 @@ void InitializeInterceptors() { TSAN_INTERCEPT(pthread_rwlock_timedwrlock); TSAN_INTERCEPT(pthread_rwlock_unlock); - // TSAN_INTERCEPT(pthread_cond_init); - TSAN_INTERCEPT(pthread_cond_destroy); - TSAN_INTERCEPT(pthread_cond_signal); - TSAN_INTERCEPT(pthread_cond_broadcast); - TSAN_INTERCEPT(pthread_cond_wait); - TSAN_INTERCEPT(pthread_cond_timedwait); + INTERCEPT_FUNCTION_VER(pthread_cond_init, pthread_cond_init_2_3_2, + GLIBC_2.3.2); + INTERCEPT_FUNCTION_VER(pthread_cond_destroy, pthread_cond_destroy_2_3_2, + GLIBC_2.3.2); + INTERCEPT_FUNCTION_VER(pthread_cond_signal, pthread_cond_signal_2_3_2, + GLIBC_2.3.2); + INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, pthread_cond_broadcast_2_3_2, + GLIBC_2.3.2); + INTERCEPT_FUNCTION_VER(pthread_cond_wait, pthread_cond_wait_2_3_2, + GLIBC_2.3.2); + INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, pthread_cond_timedwait_2_3_2, + GLIBC_2.3.2); TSAN_INTERCEPT(pthread_barrier_init); TSAN_INTERCEPT(pthread_barrier_destroy); diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc index 2ac670d60..366d5c86c 100644 --- a/lib/tsan/rtl/tsan_stat.cc +++ b/lib/tsan/rtl/tsan_stat.cc @@ -169,12 +169,15 @@ void StatOutput(u64 *stat) { name[StatInt_pthread_rwlock_timedwrlock] = " pthread_rwlock_timedwrlock "; name[StatInt_pthread_rwlock_unlock] = " pthread_rwlock_unlock "; - name[StatInt_pthread_cond_init] = " pthread_cond_init "; - name[StatInt_pthread_cond_destroy] = " pthread_cond_destroy "; - name[StatInt_pthread_cond_signal] = " pthread_cond_signal "; - name[StatInt_pthread_cond_broadcast] = " pthread_cond_broadcast "; - name[StatInt_pthread_cond_wait] = " pthread_cond_wait "; - name[StatInt_pthread_cond_timedwait] = " pthread_cond_timedwait "; + name[StatInt_pthread_cond_init_2_3_2] = " pthread_cond_init "; + name[StatInt_pthread_cond_destroy_2_3_2] + = " pthread_cond_destroy "; + name[StatInt_pthread_cond_signal_2_3_2]= " pthread_cond_signal "; + name[StatInt_pthread_cond_broadcast_2_3_2] + = " pthread_cond_broadcast "; + name[StatInt_pthread_cond_wait_2_3_2] = " pthread_cond_wait "; + name[StatInt_pthread_cond_timedwait_2_3_2] + = " pthread_cond_timedwait "; name[StatInt_pthread_barrier_init] = " pthread_barrier_init "; name[StatInt_pthread_barrier_destroy] = " pthread_barrier_destroy "; name[StatInt_pthread_barrier_wait] = " pthread_barrier_wait "; diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h index f17d83ae0..c7536f444 100644 --- a/lib/tsan/rtl/tsan_stat.h +++ b/lib/tsan/rtl/tsan_stat.h @@ -164,12 +164,12 @@ enum StatType { StatInt_pthread_rwlock_trywrlock, StatInt_pthread_rwlock_timedwrlock, StatInt_pthread_rwlock_unlock, - StatInt_pthread_cond_init, - StatInt_pthread_cond_destroy, - StatInt_pthread_cond_signal, - StatInt_pthread_cond_broadcast, - StatInt_pthread_cond_wait, - StatInt_pthread_cond_timedwait, + StatInt_pthread_cond_init_2_3_2, + StatInt_pthread_cond_destroy_2_3_2, + StatInt_pthread_cond_signal_2_3_2, + StatInt_pthread_cond_broadcast_2_3_2, + StatInt_pthread_cond_wait_2_3_2, + StatInt_pthread_cond_timedwait_2_3_2, StatInt_pthread_barrier_init, StatInt_pthread_barrier_destroy, StatInt_pthread_barrier_wait, |