NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: toolchain/59189: leak sanitizer broken
The following reply was made to PR toolchain/59189; it has been noted by GNATS.
From: RVP <rvp%SDF.ORG@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: Christos Zoulas <christos%zoulas.com@localhost>, toolchain-manager%netbsd.org@localhost
Subject: Re: toolchain/59189: leak sanitizer broken
Date: Sat, 22 Mar 2025 09:46:37 +0000 (UTC)
On Thu, 20 Mar 2025, Christos Zoulas wrote:
> So it dies jumping to 0 when trying to call the real ataxit() from __interceptor_atexit() in the call ataxit(cleanup) from crt0.
> [...]
> Something seems to be wrong with the relocation record of ataxit() but it is supposed to work
> because the dynamic linking has finished. Adding -Wl,-z,now does not help either.
>
Yeah. I think what's happening on NetBSD-HEAD is:
1. src/lib/csu/common/crt0-common.c calls atexit() before calling _preinit()--which
would've called libsanitizer/lsan/lsan_preinit.cpp:__lsan_init() to fill in
the address of the real atexit().
2. Because the LSAN atexit() isn't defined as a weak symbol, _that_ gets called
instead of the libc one--which then crashes when it calls NULL.
(I don't know why this works on NetBSD 10.x: something must be causing __lsan_init()
to be called there; or, it's fluke that it works...)
Anyway, I've come up with 2 patches. The first, just calls __lsan_init() in the
atexit() and __cxa_atexit() LSAN wrappers. (I tried using `ENSURE_LSAN_INITED'
similar to `ENSURE_ASAN_INITED', but that doesn't work for some reason...)
This is a bit of hack, but, seems to work.
```
diff -urN a/src/external/gpl3/gcc/dist/libsanitizer/lsan/lsan_interceptors.cpp b/src/external/gpl3/gcc/dist/libsanitizer/lsan/lsan_interceptors.cpp
--- a/src/external/gpl3/gcc/dist/libsanitizer/lsan/lsan_interceptors.cpp 2023-07-31 01:44:55.000000000 +0000
+++ b/src/external/gpl3/gcc/dist/libsanitizer/lsan/lsan_interceptors.cpp 2025-03-22 08:04:16.230083864 +0000
@@ -367,6 +367,8 @@
#if SANITIZER_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
+ if (!lsan_inited && !lsan_init_is_running)
+ __lsan_init();
__lsan::ScopedInterceptorDisabler disabler;
return REAL(__cxa_atexit)(func, arg, dso_handle);
}
@@ -377,6 +379,8 @@
#if SANITIZER_INTERCEPT_ATEXIT
INTERCEPTOR(int, atexit, void (*f)()) {
+ if (!lsan_inited && !lsan_init_is_running)
+ __lsan_init();
__lsan::ScopedInterceptorDisabler disabler;
return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
}
diff -urN a/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_flags.inc b/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_flags.inc
--- a/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_flags.inc 2023-07-31 01:44:56.000000000 +0000
+++ b/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_flags.inc 2025-03-22 08:13:00.083831970 +0000
@@ -28,7 +28,7 @@
"Path to external symbolizer. If empty, the tool will search $PATH for "
"the symbolizer.")
COMMON_FLAG(
- bool, allow_addr2line, false,
+ bool, allow_addr2line, true,
"If set, allows online symbolizer to run addr2line binary to symbolize "
"stack traces (addr2line will only be used if llvm-symbolizer binary is "
"unavailable.")
```
The second one is to do things the Linux way: call the `.preinit_array'
functions first, _then_ call atexit(); and provide a spec for GCC.
(Note: I haven't tested this spec...):
```
diff -urN a/src/lib/csu/common/crt0-common.c b/src/lib/csu/common/crt0-common.c
--- a/src/lib/csu/common/crt0-common.c 2024-01-19 19:22:17.000000000 +0000
+++ b/src/lib/csu/common/crt0-common.c 2025-03-22 07:51:24.617231789 +0000
@@ -317,9 +317,6 @@
__progname = empty_string;
}
- if (cleanup != NULL)
- atexit(cleanup);
-
_libc_init();
if (&rtld_DYNAMIC == NULL) {
@@ -333,6 +330,9 @@
_preinit();
+ if (cleanup != NULL)
+ atexit(cleanup);
+
#ifdef MCRT0
atexit(_mcleanup);
monstartup((u_long)&__eprol, (u_long)&__etext);
diff -urN a/src/external/gpl3/gcc/dist/gcc/config/netbsd.h b/src/external/gpl3/gcc/dist/gcc/config/netbsd.h
--- a/src/external/gpl3/gcc/dist/gcc/config/netbsd.h 2023-07-31 01:46:31.000000000 +0000
+++ b/src/external/gpl3/gcc/dist/gcc/config/netbsd.h 2025-03-22 08:18:31.573486823 +0000
@@ -204,8 +204,29 @@
netbsd_patch_builtins (); \
} while(0)
+/* Link -lasan early on the command line. For -static-libasan, don't link
+ it for -shared link, the executable should be compiled with -static-libasan
+ in that case, and for executable link with --{,no-}whole-archive around
+ it to force everything into the executable. And similarly for -ltsan,
+ -lhwasan, and -llsan. */
#if defined(HAVE_LD_STATIC_DYNAMIC)
+#undef LIBASAN_EARLY_SPEC
+#define LIBASAN_EARLY_SPEC "%{!shared:libasan_preinit%O%s} " \
+ "%{static-libasan:%{!shared:" \
+ LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \
+ LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}"
+#undef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC "%{static-libhwasan:%{!shared:" \
+ LD_STATIC_OPTION " --whole-archive -lhwasan --no-whole-archive " \
+ LD_DYNAMIC_OPTION "}}%{!static-libhwasan:-lhwasan}"
#undef LIBTSAN_EARLY_SPEC
-#define LIBTSAN_EARLY_SPEC "%{static-libtsan:" LD_STATIC_OPTION "}" \
- " -ltsan %{static-libtsan:" LD_DYNAMIC_OPTION "} -lpthread"
+#define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \
+ "%{static-libtsan:%{!shared:" \
+ LD_STATIC_OPTION " --whole-archive -ltsan --no-whole-archive " \
+ LD_DYNAMIC_OPTION "}}%{!static-libtsan:-ltsan}"
+#undef LIBLSAN_EARLY_SPEC
+#define LIBLSAN_EARLY_SPEC "%{!shared:liblsan_preinit%O%s} " \
+ "%{static-liblsan:%{!shared:" \
+ LD_STATIC_OPTION " --whole-archive -llsan --no-whole-archive " \
+ LD_DYNAMIC_OPTION "}}%{!static-liblsan:-llsan}"
#endif
```
The spec will rely on there now being files called libasan_preinit.o,
liblsan_preinit.o, etc., in the compiler-specific lib. directory--like on Linux:
```
$ find /usr/ -name lib*_preinit.o 2>/dev/null
/usr/lib/gcc/x86_64-linux-gnu/13/libhwasan_preinit.o
/usr/lib/gcc/x86_64-linux-gnu/13/libtsan_preinit.o
/usr/lib/gcc/x86_64-linux-gnu/13/libasan_preinit.o
/usr/lib/gcc/x86_64-linux-gnu/13/liblsan_preinit.o
$
```
(Some Makefile magic is surely needed for this... :))
HTH,
-RVP
PS. My test code follows:
```base64 mylsan.tar.bz2
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
50jiAkl0BojDQaQ0DOyBiX/xdyRThQkL6l1b4A==
```
Home |
Main Index |
Thread Index |
Old Index