Created attachment 21114 [details] test case Hello. Attached is a test-case for the problem. If some C++ shlib is dlopen()ed by the C program, and then this shlib throws an exception (that it also catches of course - invisible to the C code), then asan fails to find __cxa_throw, and calls the __asan_handle_no_return() in an infinite loop. Another bug here is that it is not possible to see the symbols of asan functions: --- (gdb) bt #0 0x00000000004e6bf9 in __asan::AsanThread::stack_top() () #1 0x00000000004e4785 in __asan_handle_no_return () #2 0x000000000043304c in __interceptor___cxa_throw () #3 0x00007ffff40fea9f in foo () at shlib.cpp:4 #4 0x00007ffff40fe97d in bar () at shlib.cpp:13 #5 0x00000000005121eb in main () at main.c:11 --- ... even though everything was compiled with debug info.
The reason appears simple. clang statically links asan to the main executable, and not to shared lib. As the result, we get this: --- Run till exit from #0 __dlsym (handle=0xffffffffffffffff, name=0x5195e8 "__cxa_throw") at dlsym.c:56 0x00000000004e8e85 in __interception::GetRealFunctionAddress(char const*, unsigned long*, unsigned long, unsigned long) () Value returned is $1 = (void *) 0x0 (gdb) bt #0 0x00000000004e8e85 in __interception::GetRealFunctionAddress(char const*, unsigned long*, unsigned long, unsigned long) () #1 0x00000000004d2db3 in __asan::InitializeAsanInterceptors() () #2 0x00000000004e4c84 in __asan::AsanInitInternal() [clone .part.0] () #3 0x00007ffff7de5806 in _dl_init (main_map=0x7ffff7ffe170, argc=1, argv=0x7fffffffdf08, env=0x7fffffffdf18) at dl-init.c:104 #4 0x00007ffff7dd60ca in _dl_start_user () from /lib64/ld-linux-x86-64.so.2 --- Since the main executable is not linked to libstdc++ (only the C++ shlib is linked to it), dlsym() can't resolve __cxa_throw. The additional bug, compared to gcc's asan, is that clang's one doesn't check the dlsym() failure and that leads to hangs (not sure why a hang and not a NULL deref). In gcc things are much better: it uses dynamic linking of libasan (not static, as clang), and it checks the dlsym() return, so with gcc there is only a run-time error msg.
This is still reproducible with compiler-rt master version. The infinite loop is caused by asan choosing to dlsym on its interceptor when finding next symbol fails (in your case because libstdc++ is not loaded yet). A nice way to fix that error would be to lazily load interceptors, but that would come at a small runtime cost. Adding Kostya Serebryany for more advices...
Is there an easy workaround in the build command line(s) for this program? I am reluctant to support this case if it adds further complexity to asan.
The workaround is trivial: pass `-lstdc++` to the linker when compiling the main function. That way, when asan builds its interceptors, the `__cxa_throw`` symbol is found by dlopen.
Is this somehow specific to libstdc++, or this "workaround" will have to be applied for all deps, recursively? Also, gcc's asan at least doesn't hang in an infinite loop. It prints an error and goes on, which is a big win by itself.
It's not specific to libstdc++, the issue would raise for any shared library linked into a dlopened library and not in the main executable. I agree with the error handling aspect, @kostya, any idea to improve the situation?
No good ideas, sorry, except that patches are welcome (as long as they don't add too much complexity)
@Kostya: in this snippet ``` INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { CHECK(REAL(__cxa_throw)); __asan_handle_no_return(); REAL(__cxa_throw)(a, b, c); } ``` we could check whether REAL(__cxa_throw) != __cxa_throw, which is the cause of the origin loop. Even better, if REAL(__cxa_throw) == __cxa_throw, we could try a new dlsym lookup because if the input program is correct, then __cxa_throw must be available when called. Taking this one step further, there is no need to run the dlsym at startup, it could be done lazily upon first call :-)
I'd like to avoid any kind of lazy init, it usually adds complexity more than it removes it. If you can come up with a simple check in the interceptor, and a test, please submit a patch.
https://reviews.llvm.org/D63877 now raises a decent error
Fixed by https://reviews.llvm.org/rL366413