From 195b0fe7eab2e836bfaed71ff019b10a29ba15a4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 17 Nov 2020 23:43:08 -0800 Subject: [PATCH] [tsan] Add pthread_cond_clockwait interceptor Disable the test on old systems. pthread_cond_clockwait is supported by glibc-2.30. It also supported by Android api 30 even though we do not run tsan on Android. Fixes https://github.com/google/sanitizers/issues/1259 Reviewed By: dvyukov --- lib/tsan/rtl/tsan_interceptors_posix.cpp | 17 +++++++++++++ test/lit.common.cfg.py | 14 +++++------ test/tsan/Linux/clockwait_double_lock.c | 32 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 test/tsan/Linux/clockwait_double_lock.c diff --git a/lib/tsan/rtl/tsan_interceptors_posix.cpp b/lib/tsan/rtl/tsan_interceptors_posix.cpp index 176dbb7ee..d1cde7d46 100644 --- a/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -1202,6 +1202,21 @@ INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { m); } +#if SANITIZER_LINUX +INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m, + __sanitizer_clockid_t clock, void *abstime) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime); + return cond_wait( + thr, pc, &si, + [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); }, + cond, m); +} +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait) +#else +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT +#endif + #if SANITIZER_MAC INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m, void *reltime) { @@ -2716,6 +2731,8 @@ void InitializeInterceptors() { TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); + TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT; + TSAN_INTERCEPT(pthread_mutex_init); TSAN_INTERCEPT(pthread_mutex_destroy); TSAN_INTERCEPT(pthread_mutex_trylock); diff --git a/test/lit.common.cfg.py b/test/lit.common.cfg.py index 77d818aa7..889e29341 100644 --- a/test/lit.common.cfg.py +++ b/test/lit.common.cfg.py @@ -360,10 +360,10 @@ def get_macos_aligned_version(macos_vers): except ValueError: lit_config.fatal("Failed to read ro.build.version.sdk (using '%s' as adb): got '%s'" % (adb, android_api_level_str)) android_api_level = min(android_api_level, int(config.android_api_level)) - if android_api_level >= 26: - config.available_features.add('android-26') - if android_api_level >= 28: - config.available_features.add('android-28') + for required in [26, 28, 30]: + if android_api_level >= required: + config.available_features.add('android-%s' % required) + # FIXME: Replace with appropriate version when availible. if android_api_level > 30 or (android_api_level == 30 and android_api_codename == 'S'): config.available_features.add('android-thread-properties-api') @@ -389,9 +389,9 @@ def get_macos_aligned_version(macos_vers): if not config.android and ver_line.startswith(b"ldd "): from distutils.version import LooseVersion ver = LooseVersion(ver_line.split()[-1].decode()) - # 2.27 introduced some incompatibilities - if ver >= LooseVersion("2.27"): - config.available_features.add("glibc-2.27") + for required in ["2.27", "2.30"]: + if ver >= LooseVersion(required): + config.available_features.add("glibc-" + required) sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): diff --git a/test/tsan/Linux/clockwait_double_lock.c b/test/tsan/Linux/clockwait_double_lock.c new file mode 100644 index 000000000..8b3edab82 --- /dev/null +++ b/test/tsan/Linux/clockwait_double_lock.c @@ -0,0 +1,32 @@ +// Regression test for https://github.com/google/sanitizers/issues/1259 +// RUN: %clang_tsan -O1 %s -o %t && %run %t +// REQUIRES: glibc-2.30 || android-30 + +#define _GNU_SOURCE +#include + +pthread_cond_t cv; +pthread_mutex_t mtx; + +void *fn(void *vp) { + pthread_mutex_lock(&mtx); + pthread_cond_signal(&cv); + pthread_mutex_unlock(&mtx); + return NULL; +} + +int main() { + pthread_mutex_lock(&mtx); + + pthread_t tid; + pthread_create(&tid, NULL, fn, NULL); + + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec += 10; + pthread_cond_clockwait(&cv, &mtx, CLOCK_MONOTONIC, &ts); + pthread_mutex_unlock(&mtx); + + pthread_join(tid, NULL); + return 0; +}