I'm faced a strange runtime behavior on Ubuntu 20.04 (gcc v 9.3.0) when using dlsym()
call.
Please, see below a simple example:
- file test.cpp:
#include <iostream>
#include <dlfcn.h>
#include <execinfo.h>
#include <typeinfo>
#include <string>
#include <memory>
#include <cxxabi.h>
#include <cstdlib>
extern "C"
{
void __cxa_throw(void *ex, void *info, void (*dest)(void *))
{
std::cout << "__cxa_throw() invoked \n";
static void (*const rethrow)(void *, void *, void (*)(void *)) __attribute__((noreturn))
= (void (*)(void *, void *, void (*)(void *)))dlsym(RTLD_NEXT, "__cxa_throw");
std::cout << "addr in lib=" << &rethrow << "\n";
rethrow(ex, info, dest);
std::terminate();
}
}
- file main.cpp:
#include <iostream>
void foo()
{
throw std::runtime_error("error");
}
int main()
{
foo();
return 0;
}
Build these 2 files as following:
g++ -fPIC -std=c++17 test.cpp -g -c -o test.o
g++ -shared ./test.o -o libtest.so
g++ main.cpp -std=c++17 -g -pedantic -L./ -ltest -ldl
Feeding ldd to ./a.out gives :
ldd a.out
linux-vdso.so.1 (0x00007ffe01186000)
/usr/local/lib/AppProtection/libAppProtection.so (0x00007f1dbd738000)
libtest.so (0x00007f1dbd733000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1dbd708000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1dbd526000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1dbd50b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1dbd319000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1dbd2f4000)
libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f1dbd1b7000)
libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f1dbd18d000)
libXi.so.6 => /lib/x86_64-linux-gnu/libXi.so.6 (0x00007f1dbd17b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1dbd964000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1dbd02c000)
libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007f1dbd024000)
libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f1dbd01c000)
libXext.so.6 => /lib/x86_64-linux-gnu/libXext.so.6 (0x00007f1dbd007000)
libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f1dbcfed000)
We can see that libtest.so
is resolved before libstdc++.so
.
My expectation how this code should work :
__cxa_throw()
is defined in 2 shared libraries :libtest.so
andlibstdc++.so
- when exception is being thrown in
foo()
call, the__cxa_throw
is resolved fromlibtest.so
and invoked. - invoking
dlsym(RTLD_NEXT, "__cxa_throw");
makes lookup for__cxa_throw
further in the list of shared libraries, found in libstdc++.so and invoked.
This works as expected on all platforms except Ubuntu 20.04 where rethrow
is referencing the __cxa_throw
from libtest.so
(but not libstc++.so
) and thus causing endless recursion.
Please assist as I'm puzzled with runtime behavior.
dlsym( RTLD_DEFAULT, "__cxa_throw" );
beforedlsym( RTLD_NEXT, ... );
? – Therm/usr/local/lib/AppProtection/libAppProtection.so
? Does that exist on systems that don't have problems withdlsym()
? You might want to see whichdlsym()
you're calling... – Apostrophesudo apt-get purge icaclient
followed by rebooting make it work? Does it work if you try it on a fresh install of Ubuntu 20.04? – Utticaicaclient
helped. This is very unexpected hook made by citrix client. Thank for help! – Amato