在使用 dlsym()
调用时,我面对着 Ubuntu 20.04(gcc 版本为 9.3.0)上的奇怪运行时行为。
请看下面的简单示例:
- 文件 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();
}
}
- 文件 main.cpp:
#include <iostream>
void foo()
{
throw std::runtime_error("error");
}
int main()
{
foo();
return 0;
}
请按照以下步骤构建这2个文件:
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
将 ldd 命令传递给 ./a.out,将会得到以下结果:
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)
我们可以看到在
libstdc++.so
之前,libtest.so
被解析出来了。
我期望代码的工作方式如下:
__cxa_throw()
在两个共享库中都有定义:libtest.so
和libstdc++.so
- 当在
foo()
调用中抛出异常时,__cxa_throw
将从libtest.so
中解析并调用。 - 调用
dlsym(RTLD_NEXT, "__cxa_throw");
会在共享库列表中进一步查找__cxa_throw
,并在libstdc++.so
中找到并调用。
rethrow
引用了libtest.so
中的__cxa_throw
(但不是libstc++.so
),从而导致无限递归。
请协助解决运行时行为问题。
dlsym( RTLD_NEXT, ... );
之前先调用dlsym( RTLD_DEFAULT, "__cxa_throw" );
吗? - Ingo Leonhardt/usr/local/lib/AppProtection/libAppProtection.so
是什么?在没有dlsym()
问题的系统上是否存在?您可能想查看您正在调用哪个dlsym()
... - Andrew Henlesudo apt-get purge icaclient
并重新启动,它是否能够正常工作?如果您在新安装的Ubuntu 20.04上尝试,它是否能够正常工作? - Joseph Sible-Reinstate Monicaicaclient
很有帮助。这是由 Citrix 客户端制作的非常意外的钩子。感谢您的帮助! - drus