Ubuntu 20.04环境下dlsym()结合RTLD_NEXT未按预期运行问题
Ubuntu 20.04下dlsym(RTLD_NEXT)查找__cxa_throw触发无限递归的原因和解决方案
问题根因
你遇到的无限递归问题本质是ldd输出中前置加载的/usr/local/lib/AppProtection/libAppProtection.so篡改了dlsym的标准实现:
- 该库是Citrix Workspace的应用保护组件,默认会注入到所有用户进程中,内部hook了
dlsym函数,破坏了RTLD_NEXT的原生查找逻辑——原本RTLD_NEXT会跳过当前调用dlsym的库,从后续加载的库中查找符号,但被篡改后的实现没有跳过当前的libtest.so,直接返回了你自己实现的__cxa_throw地址,导致递归调用。 - 干净无Citrix组件的Ubuntu 20.04环境下,你给出的代码可以正常运行,符合你预期的逻辑。
问题验证
你可以通过以下操作确认根因:
- 临时卸载Citrix AppProtection组件,重新运行程序,递归问题会消失
- 运行程序时指定
LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6,强制让libstdc++的符号优先级高于其他注入库,也可临时解决递归问题
兼容修复方案
如果你不能卸载Citrix组件,可以改用直接查找libstdc++导出符号的方式绕过被篡改的RTLD_NEXT逻辑,修改test.cpp中rethrow的初始化逻辑即可:
#include <functional> 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)) = [](){ // 直接打开已加载的libstdc++.so.6,不会触发重复加载 void* libstdcpp = dlopen("libstdc++.so.6", RTLD_LAZY | RTLD_NOLOAD); if (!libstdcpp) { std::terminate(); } auto func = dlsym(libstdcpp, "__cxa_throw"); dlclose(libstdcpp); return reinterpret_cast<void (*)(void *, void *, void (*)(void *))>(func); }(); std::cout << "addr in lib=" << reinterpret_cast<void*>(rethrow) << "\n"; rethrow(ex, info, dest); std::terminate(); } }
内容的提问来源于stack exchange,提问作者drus
相关产品推荐
相关产品推荐

