tsan: Refine conditions to intercept pthread_cond_t functions

On glibc x86-64, functions like pthread_cond_init exist in two versions:
2.2 (older pthread_cond_t) and 2.3.2 (newer pthread_cond_t). In glibc
versions prior to 2.36, using an unversioned interceptor
(`dlsym(RTLD_NEXT, "pthread_cond_init")`) retrieves the older 2.2
symbol, which is not desired
(https://sourceware.org/bugzilla/show_bug.cgi?id=14932).

For newer architectures, such as aarch64 (introduced in glibc 2.17) and
riscv64 (introduced in glibc 2.27), a versioned interceptor is
unnecessary.

Pull Request: https://github.com/llvm/llvm-project/pull/154268
This commit is contained in:
Fangrui Song 2025-08-19 20:07:23 -07:00 committed by GitHub
parent 1fb2331e82
commit c940c242fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 22 deletions

View File

@ -312,12 +312,24 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock);
INTERCEPT_FUNCTION(pthread_rwlock_unlock);
// See the comment in tsan_interceptors_posix.cpp.
#if SANITIZER_GLIBC && !__GLIBC_PREREQ(2, 36) && \
(defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \
defined(__s390x__))
INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
#else
INTERCEPT_FUNCTION(pthread_cond_init);
INTERCEPT_FUNCTION(pthread_cond_signal);
INTERCEPT_FUNCTION(pthread_cond_broadcast);
INTERCEPT_FUNCTION(pthread_cond_wait);
INTERCEPT_FUNCTION(pthread_cond_timedwait);
INTERCEPT_FUNCTION(pthread_cond_destroy);
#endif
// for symbolizer
INTERCEPT_FUNCTION(realpath);

View File

@ -79,17 +79,6 @@ struct ucontext_t {
};
#endif
#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \
defined(__s390x__)
#define PTHREAD_ABI_BASE "GLIBC_2.3.2"
#elif defined(__aarch64__) || SANITIZER_PPC64V2
#define PTHREAD_ABI_BASE "GLIBC_2.17"
#elif SANITIZER_LOONGARCH64
#define PTHREAD_ABI_BASE "GLIBC_2.36"
#elif SANITIZER_RISCV64
# define PTHREAD_ABI_BASE "GLIBC_2.27"
#endif
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
@ -341,11 +330,6 @@ void ScopedInterceptor::DisableIgnoresImpl() {
}
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
#else
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
#endif
#if SANITIZER_FREEBSD
# define TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(func) \
INTERCEPT_FUNCTION(_pthread_##func)
@ -3041,12 +3025,26 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_timedjoin_np);
#endif
TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
// In glibc versions older than 2.36, dlsym(RTLD_NEXT, "pthread_cond_init")
// may return an outdated symbol (max(2.2,base_version)) if the port was
// introduced before 2.3.2 (when the new pthread_cond_t was introduced).
#if SANITIZER_GLIBC && !__GLIBC_PREREQ(2, 36) && \
(defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \
defined(__s390x__))
INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
#else
INTERCEPT_FUNCTION(pthread_cond_init);
INTERCEPT_FUNCTION(pthread_cond_signal);
INTERCEPT_FUNCTION(pthread_cond_broadcast);
INTERCEPT_FUNCTION(pthread_cond_wait);
INTERCEPT_FUNCTION(pthread_cond_timedwait);
INTERCEPT_FUNCTION(pthread_cond_destroy);
#endif
TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;