forked from OSchip/llvm-project
[asan] Versioned interceptor for pthread_create.
This fixes a crash in pthread_create on linux/i386 due to abi incompatibility between intercepted and non-intercepted functions. See the test case for more details. llvm-svn: 248325
This commit is contained in:
parent
1d6063e804
commit
9147de0ddf
|
@ -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 @@ void InitializeAsanInterceptors() {
|
|||
|
||||
// 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
|
||||
|
||||
|
|
|
@ -98,6 +98,12 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
|||
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)
|
||||
|
|
|
@ -35,12 +35,12 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
|
|||
(::__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
|
||||
|
|
|
@ -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 <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue