Skip to content

Commit 8827047

Browse files
committed
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 llvm-svn: 372459
1 parent 0468293 commit 8827047

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

compiler-rt/lib/asan/asan_interceptors.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,24 +560,58 @@ INTERCEPTOR(long long, atoll, const char *nptr) {
560560
}
561561
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
562562

563-
#if ASAN_INTERCEPT___CXA_ATEXIT
563+
#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
564564
static void AtCxaAtexit(void *unused) {
565565
(void)unused;
566566
StopInitOrderChecking();
567567
}
568+
#endif
568569

570+
#if ASAN_INTERCEPT___CXA_ATEXIT
569571
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
570572
void *dso_handle) {
571573
#if SANITIZER_MAC
572574
if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
573575
#endif
574576
ENSURE_ASAN_INITED();
577+
#if CAN_SANITIZE_LEAKS
578+
__lsan::ScopedInterceptorDisabler disabler;
579+
#endif
575580
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
576581
REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
577582
return res;
578583
}
579584
#endif // ASAN_INTERCEPT___CXA_ATEXIT
580585

586+
#if ASAN_INTERCEPT_ATEXIT
587+
INTERCEPTOR(int, atexit, void (*func)()) {
588+
ENSURE_ASAN_INITED();
589+
#if CAN_SANITIZE_LEAKS
590+
__lsan::ScopedInterceptorDisabler disabler;
591+
#endif
592+
// Avoid calling real atexit as it is unrechable on at least on Linux.
593+
int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
594+
REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
595+
return res;
596+
}
597+
#endif
598+
599+
#if ASAN_INTERCEPT_PTHREAD_ATFORK
600+
extern "C" {
601+
extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
602+
void (*child)());
603+
};
604+
605+
INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
606+
void (*child)()) {
607+
#if CAN_SANITIZE_LEAKS
608+
__lsan::ScopedInterceptorDisabler disabler;
609+
#endif
610+
// REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD
611+
return _pthread_atfork(prepare, parent, child);
612+
}
613+
#endif
614+
581615
#if ASAN_INTERCEPT_VFORK
582616
DEFINE_REAL(int, vfork)
583617
DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
@@ -660,6 +694,14 @@ void InitializeAsanInterceptors() {
660694
ASAN_INTERCEPT_FUNC(__cxa_atexit);
661695
#endif
662696

697+
#if ASAN_INTERCEPT_ATEXIT
698+
ASAN_INTERCEPT_FUNC(atexit);
699+
#endif
700+
701+
#if ASAN_INTERCEPT_PTHREAD_ATFORK
702+
ASAN_INTERCEPT_FUNC(pthread_atfork);
703+
#endif
704+
663705
#if ASAN_INTERCEPT_VFORK
664706
ASAN_INTERCEPT_FUNC(vfork);
665707
#endif

compiler-rt/lib/asan/asan_interceptors.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ void InitializePlatformInterceptors();
9999
# define ASAN_INTERCEPT___CXA_ATEXIT 0
100100
#endif
101101

102+
#if SANITIZER_NETBSD
103+
# define ASAN_INTERCEPT_ATEXIT 1
104+
#else
105+
# define ASAN_INTERCEPT_ATEXIT 0
106+
#endif
107+
102108
#if SANITIZER_LINUX && !SANITIZER_ANDROID
103109
# define ASAN_INTERCEPT___STRDUP 1
104110
#else
@@ -112,6 +118,12 @@ void InitializePlatformInterceptors();
112118
# define ASAN_INTERCEPT_VFORK 0
113119
#endif
114120

121+
#if SANITIZER_NETBSD
122+
# define ASAN_INTERCEPT_PTHREAD_ATFORK 1
123+
#else
124+
# define ASAN_INTERCEPT_PTHREAD_ATFORK 0
125+
#endif
126+
115127
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
116128
DECLARE_REAL(char*, strchr, const char *str, int c)
117129
DECLARE_REAL(SIZE_T, strlen, const char *s)

compiler-rt/lib/lsan/lsan_interceptors.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,44 @@ INTERCEPTOR(void, thr_exit, tid_t *state) {
345345
#define LSAN_MAYBE_INTERCEPT_THR_EXIT
346346
#endif
347347

348+
#if SANITIZER_INTERCEPT___CXA_ATEXIT
349+
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
350+
void *dso_handle) {
351+
__lsan::ScopedInterceptorDisabler disabler;
352+
return REAL(__cxa_atexit)(func, arg, dso_handle);
353+
}
354+
#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
355+
#else
356+
#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
357+
#endif
358+
359+
#if SANITIZER_INTERCEPT_ATEXIT
360+
INTERCEPTOR(int, atexit, void (*f)()) {
361+
__lsan::ScopedInterceptorDisabler disabler;
362+
return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
363+
}
364+
#define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
365+
#else
366+
#define LSAN_MAYBE_INTERCEPT_ATEXIT
367+
#endif
368+
369+
#if SANITIZER_INTERCEPT_PTHREAD_ATFORK
370+
extern "C" {
371+
extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
372+
void (*child)());
373+
};
374+
375+
INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
376+
void (*child)()) {
377+
__lsan::ScopedInterceptorDisabler disabler;
378+
// REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD
379+
return _pthread_atfork(prepare, parent, child);
380+
}
381+
#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
382+
#else
383+
#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
384+
#endif
385+
348386
struct ThreadParam {
349387
void *(*callback)(void *arg);
350388
void *param;
@@ -454,6 +492,10 @@ void InitializeInterceptors() {
454492
LSAN_MAYBE_INTERCEPT__LWP_EXIT;
455493
LSAN_MAYBE_INTERCEPT_THR_EXIT;
456494

495+
LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
496+
LSAN_MAYBE_INTERCEPT_ATEXIT;
497+
LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
498+
457499
#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
458500
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
459501
Report("LeakSanitizer: failed to create thread key.\n");

compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,5 +567,9 @@
567567
#define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD)
568568

569569
#define SANITIZER_INTERCEPT_GETRANDOM SI_LINUX
570+
#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD
571+
#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD
572+
#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
573+
570574

571575
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H

0 commit comments

Comments
 (0)