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
 QlpoOTFBWSZTWb6l1b4AB7p/gtywEKB79/+fb+f+5P/v3/pAAAAIYAhfAAAAAAAAAAAOGhk00NMj
 Q0yMgyMjQyAxNGTQBkyMQxw0MmmhpkaGmRkGRkaGQGJoyaAMmRiGOGhk00NMjQ0yMgyMjQyAxNGT
 QBkyMQxw0MmmhpkaGmRkGRkaGQGJoyaAMmRiGOGhk00NMjQ0yMgyMjQyAxNGTQBkyMQwkSBATQEA
 EwQaJMmT00mgeoHqGjGhNNlK/H7RM/p/Zn+JdHSjtsK5UB3iBHdSvZLv4IUxB3ne3E6x3234TExK
 9IYk1AsRGx+7X8Ph6N/D7yZPxug8jub+QupOawviRFIkVsenAy+wlefgfcUng2W9LhNjGli2yCI9
 RMlKcOqWSaox/RWE5HveI1If4sNg6sZNBQ5AOQEj8RNAqoFZoReci9YV4z7822BB830AfSmFOAYl
 kchlrJk0jTIG9Vucf2324H4u3eXRz4GHTOm8zONGboLpvVgfMxRLeFDiUuVMgbOMeUzMehjebtJW
 DjPHKLEZGWZsvcEzXBF9r7yNZlYvovJUrDHuwgzbulxf5NDVs11OYlrJm03mrYQfoezT8itB+Ewt
 jMkXxu4rGiNFBfThZ6xZDOLA5TM2yM5N1FMg2kyCR7jQsXaiDWFxJMmQchcTi8rdUolZ8AYaZkAa
 FUQa8MtefEI8pgfXbguskskuDDeDBpSsNIGmHYkfFsY3IMF3RkCyulxqGccMG4MkmH4KjWbHcqzB
 S60sCRqIKYbrVcVkA2kwkXShQLfWJWh1Pc/m0KB1JnYoytSJRRkgMg1qR29AZzsrsh70pEmWqE0Q
 D13lqkKoxioQSVoyc8gp0EAzMs0JjE2DA74/cxYBYLgw1Qdxr1dm0oNtnSTOI2rr3XylmgwDUSDj
 P0PiHabhEj2kCsMMBnKOCsNG3VvjhsPJhGkDIOeBZfnE3KkUiB8cqIYdCAuNQ+cTlASGSoiSPYhf
 OLr9cAvWj6YAXv97+77/y1CCoJiYL95dhGeedRULCcAs6frJ+t3ntGem7J0o6zDHCsibGTICgsr5
 zBUdcnOkkXF08rCm6T9tigyRAWBYzFhu05jwUo8wdjOgZ1sR53NhNhunCJm8S+gYMGL0+VgcJB/s
 VxmvuDuPnF42NaR/sXvRX7Rbkehei4PCrCF7mjcsQyfqSPOkenWiyPP4lx9/J/GvynFP1BMGuClM
 /I1jGNn4pEzlR7xXrMOZFCnsxPZ/IkfXBwA0SOUDwOsaba9ejaFU6xw2PgNKJ+ShH7puJESc5y7w
 14fmm2xDYxmLGNtYCQelHlISU7KUypYNt/o4hfEBXEzE1f8rG0p6qjhZ5HkD+SXEf9YHwaS3Y3t/
 BSNYLeNir8/6xiIatJEFSZ7VUWoVVMzLiT2htsGQYVDkKFm2LoGR8sQNGsYlDOjGOvRbSQHBLLTQ
 DpGGOIzpJAvQLaFgxmeFBuJCmNBzbi9bgokiowkGNkGrcsNYuKgGuQCwEKbJxCGxrgzj3lkjyjE1
 zIIuyCy2JaGsoK8+SY2UTNlEfnWa6mNnIJFOcJchtyqvibyBc51NcQfCvWTF1jJl5GqmJDZUkENS
 IgIGv7LYBgXCPUmIqVMlK6M6BgoSX92VAp80Gw/8jd3pI0MGazAkpIFcj4IaWokkkcpxIOhLP6jy
 kqpHMHPwsbAqlK8IkyJkvCE7A5QDGzImwM0PtLdp4LgDXymkiQoPKiS5pBkxLqGlsRNJgZgSXWb0
 gOQ5Vf6BwdCMPLsD3JYhBYaKoKZisDLv8l2zmSbsdOIxseiaKAtiReXJEzYPwS+REJiDmGAd5AoG
 xsGmwlolYaZibUyRBAMTa8oYoJDUhKplzzRwOUkG6dgf6rjcwwFkXJWTGXdU672iZxJEliB1JZoO
 cFrqBcavGD/WZoaJKZrIFr2h9Pv/PD/32XazKIXolASIPikZohg1vmkRJQuQ/DYHK34vxLdBzgGC
 BgYd+KJyREC8eUhBc0jYmVCx2Gr7iZjcrIJJgXJgmmkTPSbzuI87GQZwN9WBmXlqNosVMzzJAdyv
 SGLA78Ei+7lW0gOxLIFkU9MlovQM0Bbzcj4hv8yW4N2vYLULSZ4ixDp81A8/L9R8nsKC8iSNwC7T
 vyF1c0J1JCHDGwahRABERBHWCkbxi6BdIcuQrJIvC5M3T+ltqGH7RjHPmA7jUjbQVEagKpGFMTal
 2HNdVXnAXxFMMTuLxNdR2mkVB72zwO1aCWZVnmxy15pZzDqVhmpFZi2oqoF1r6kXGYFFghi2LepS
 OJMg/LYFkpAgoNIyITUJai8SzAvLhpI+chJIhIeQCsoVSZLwBjRMgoHQYoEQLcAydAK5JSSsGxW1
 INZcl5EvcNJpjWPKNftGlyADvSvFCGLuF2gajGyqDzaFCRBCWALM0KLYwoNdow2gKiSR7WXBholB
 50jiAkl0BojDQaQ0DOyBiX/xdyRThQkL6l1b4A==
 ```
 


Home | Main Index | Thread Index | Old Index