You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 04:45:03