forked from OSchip/llvm-project
tsan: properly intercept pthread_cond functions
llvm-svn: 189767
This commit is contained in:
parent
63872ce19f
commit
3a6c7cea77
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
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_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_signal, void *c) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, c);
|
||||
int res = REAL(pthread_cond_signal)(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_broadcast, void *c) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, c);
|
||||
int res = REAL(pthread_cond_broadcast)(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_wait, void *c, void *m) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, c, m);
|
||||
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_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);
|
||||
|
|
|
@ -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 ";
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue