summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Rytarowski <n54@gmx.com>2019-09-21 07:30:42 +0000
committerKamil Rytarowski <n54@gmx.com>2019-09-21 07:30:42 +0000
commit96b852a95bebc7c2d9da09975a4764c365167621 (patch)
treeef6cf465bc7fac9830d1ba6a74ab43472b7a0681
parentdc2e8074dc573a070e71da4be3d97c5f6b765dba (diff)
downloadcompiler-rt-96b852a95bebc7c2d9da09975a4764c365167621.tar.gz
Stop tracking atexit/__cxa_atexit/pthread_atfork allocations in LSan/NetBSD
Summary: The atexit(3) and __cxa_atexit() calls allocate internally memory and free on exit, after executing all callback. This causes false positives as DoLeakCheck() is called from the atexit handler. In the LSan/ASan tests there are strict checks triggering false positives here. Intercept all atexit(3) and __cxa_atexit() calls and disable LSan when calling the real functions. Stop tracing allocations in pthread_atfork(3) funtions, as there are performed internal allocations that are not freed for the time of running StopTheWorld() code. This avoids false-positives. The same changes have to be replicated in the ASan and LSan runtime. Non-NetBSD OSs are not tested and this code is restricted to NetBSD only. Reviewers: dvyukov, joerg, mgorny, vitalybuka, eugenis Reviewed By: vitalybuka Subscribers: jfb, llvm-commits, #sanitizers Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D67331 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@372459 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_interceptors.cpp44
-rw-r--r--lib/asan/asan_interceptors.h12
-rw-r--r--lib/lsan/lsan_interceptors.cpp42
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h4
4 files changed, 101 insertions, 1 deletions
diff --git a/lib/asan/asan_interceptors.cpp b/lib/asan/asan_interceptors.cpp
index cea4d63e6..ec9589338 100644
--- a/lib/asan/asan_interceptors.cpp
+++ b/lib/asan/asan_interceptors.cpp
@@ -560,24 +560,58 @@ INTERCEPTOR(long long, atoll, const char *nptr) {
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
-#if ASAN_INTERCEPT___CXA_ATEXIT
+#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
static void AtCxaAtexit(void *unused) {
(void)unused;
StopInitOrderChecking();
}
+#endif
+#if ASAN_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
#if SANITIZER_MAC
if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
#endif
ENSURE_ASAN_INITED();
+#if CAN_SANITIZE_LEAKS
+ __lsan::ScopedInterceptorDisabler disabler;
+#endif
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
return res;
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
+#if ASAN_INTERCEPT_ATEXIT
+INTERCEPTOR(int, atexit, void (*func)()) {
+ ENSURE_ASAN_INITED();
+#if CAN_SANITIZE_LEAKS
+ __lsan::ScopedInterceptorDisabler disabler;
+#endif
+ // Avoid calling real atexit as it is unrechable on at least on Linux.
+ int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
+ REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
+ return res;
+}
+#endif
+
+#if ASAN_INTERCEPT_PTHREAD_ATFORK
+extern "C" {
+extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
+ void (*child)());
+};
+
+INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
+ void (*child)()) {
+#if CAN_SANITIZE_LEAKS
+ __lsan::ScopedInterceptorDisabler disabler;
+#endif
+ // REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD
+ return _pthread_atfork(prepare, parent, child);
+}
+#endif
+
#if ASAN_INTERCEPT_VFORK
DEFINE_REAL(int, vfork)
DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
@@ -660,6 +694,14 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
+#if ASAN_INTERCEPT_ATEXIT
+ ASAN_INTERCEPT_FUNC(atexit);
+#endif
+
+#if ASAN_INTERCEPT_PTHREAD_ATFORK
+ ASAN_INTERCEPT_FUNC(pthread_atfork);
+#endif
+
#if ASAN_INTERCEPT_VFORK
ASAN_INTERCEPT_FUNC(vfork);
#endif
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 155ea4156..344a64bd8 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -99,6 +99,12 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT___CXA_ATEXIT 0
#endif
+#if SANITIZER_NETBSD
+# define ASAN_INTERCEPT_ATEXIT 1
+#else
+# define ASAN_INTERCEPT_ATEXIT 0
+#endif
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
# define ASAN_INTERCEPT___STRDUP 1
#else
@@ -112,6 +118,12 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_VFORK 0
#endif
+#if SANITIZER_NETBSD
+# define ASAN_INTERCEPT_PTHREAD_ATFORK 1
+#else
+# define ASAN_INTERCEPT_PTHREAD_ATFORK 0
+#endif
+
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(SIZE_T, strlen, const char *s)
diff --git a/lib/lsan/lsan_interceptors.cpp b/lib/lsan/lsan_interceptors.cpp
index f06d5fff7..84a6acda4 100644
--- a/lib/lsan/lsan_interceptors.cpp
+++ b/lib/lsan/lsan_interceptors.cpp
@@ -345,6 +345,44 @@ INTERCEPTOR(void, thr_exit, tid_t *state) {
#define LSAN_MAYBE_INTERCEPT_THR_EXIT
#endif
+#if SANITIZER_INTERCEPT___CXA_ATEXIT
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+ __lsan::ScopedInterceptorDisabler disabler;
+ return REAL(__cxa_atexit)(func, arg, dso_handle);
+}
+#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
+#else
+#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
+#endif
+
+#if SANITIZER_INTERCEPT_ATEXIT
+INTERCEPTOR(int, atexit, void (*f)()) {
+ __lsan::ScopedInterceptorDisabler disabler;
+ return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
+}
+#define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
+#else
+#define LSAN_MAYBE_INTERCEPT_ATEXIT
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATFORK
+extern "C" {
+extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
+ void (*child)());
+};
+
+INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
+ void (*child)()) {
+ __lsan::ScopedInterceptorDisabler disabler;
+ // REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD
+ return _pthread_atfork(prepare, parent, child);
+}
+#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
+#else
+#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
+#endif
+
struct ThreadParam {
void *(*callback)(void *arg);
void *param;
@@ -454,6 +492,10 @@ void InitializeInterceptors() {
LSAN_MAYBE_INTERCEPT__LWP_EXIT;
LSAN_MAYBE_INTERCEPT_THR_EXIT;
+ LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
+ LSAN_MAYBE_INTERCEPT_ATEXIT;
+ LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
+
#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
Report("LeakSanitizer: failed to create thread key.\n");
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index cf079c435..c3b6f2855 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -567,5 +567,9 @@
#define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD)
#define SANITIZER_INTERCEPT_GETRANDOM SI_LINUX
+#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD
+#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD
+#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
+
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H