Index: lib/asan/asan_interceptors.h =================================================================== --- lib/asan/asan_interceptors.h +++ lib/asan/asan_interceptors.h @@ -98,6 +98,12 @@ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ } while (0) +#define ASAN_INTERCEPT_FUNC_VER(name, ver) \ + do { \ + if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \ + VReport( \ + 1, "AddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \ + } while (0) #else // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. #define ASAN_INTERCEPT_FUNC(name) Index: lib/asan/asan_interceptors.cc =================================================================== --- lib/asan/asan_interceptors.cc +++ lib/asan/asan_interceptors.cc @@ -27,6 +27,10 @@ #include "sanitizer_common/sanitizer_posix.h" #endif +#if defined(__i386) && SANITIZER_LINUX +#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" +#endif + namespace __asan { // Return true if we can quickly decide that the region is unpoisoned. @@ -791,7 +795,11 @@ // Intercept threading-related functions #if ASAN_INTERCEPT_PTHREAD_CREATE +#if defined(ASAN_PTHREAD_CREATE_VERSION) + ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); +#else ASAN_INTERCEPT_FUNC(pthread_create); +#endif ASAN_INTERCEPT_FUNC(pthread_join); #endif Index: lib/interception/interception_linux.h =================================================================== --- lib/interception/interception_linux.h +++ lib/interception/interception_linux.h @@ -35,12 +35,12 @@ (::__interception::uptr) & WRAP(func)) #if !defined(__ANDROID__) // android does not have dlvsym -# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ - ::__interception::real_##func = (func##_f)(unsigned long) \ - ::__interception::GetFuncAddrVer(#func, symver) +#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ + (::__interception::real_##func = (func##_f)( \ + unsigned long)::__interception::GetFuncAddrVer(#func, symver)) #else -# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ - INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) +#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ + INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) #endif // !defined(__ANDROID__) #endif // INTERCEPTION_LINUX_H Index: test/asan/TestCases/Linux/pthread_create_version.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Linux/pthread_create_version.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx_asan -std=c++11 %s -o %t && %run %t 2>&1 +// Regression test for the versioned pthread_create interceptor on linux/i386. +// pthread_attr_init is not intercepted and binds to the new abi +// pthread_create is intercepted; dlsym always returns the oldest version. +// This results in a crash inside pthread_create in libc. + +#include +#include + +void *ThreadFunc(void *) { return nullptr; } + +int main() { + pthread_t t; + const size_t sz = 1024 * 1024; + void *p = malloc(sz); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstack(&attr, p, sz); + pthread_create(&t, &attr, ThreadFunc, nullptr); + pthread_join(t, nullptr); + free(p); + return 0; +}