【问题标题】:How to know if process has truly finished with a dlclose()ed library?如何知道进程是否真正完成了 dlclose()ed 库?
【发布时间】:2012-06-14 21:32:02
【问题描述】:

我在 Linux (Ubuntu 12.04, gcc 4.6.3) 上,试图弯曲 dlopen/close 以创建一个基于插件的应用程序,该应用程序可以在必要时重新加载其插件(例如,如果他们'重新编译)。

基本原理很简单:dlopen插件;使用它,跟踪所有正在使用的符号。当需要重新加载时,清理所有符号并关闭插件。

我拼凑了一个简单的演示应用程序“test.cpp”:

#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
    if (argc > 1)
    {
        void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL);
        if (!h)
        {
            cerr << "ERROR: " << dlerror() << endl;
            return 1;
        }
        cin.get();
        if (dlclose(h))
        {
            cerr << "ERROR: " << dlerror() << endl;
            return 2;
        }
        cin.get();
    }
    return 0;
}

编译:

g++ test.cpp -o test -ldl

要创建一个可以作为参数传递给上述代码的简单库,请使用:

touch libtest.cpp && g++ -rdynamic -shared libtest.cpp -o libtest.so

然后运行:

./test ./libtest.so

这就是问题所在;如果在点击 [Enter] 一次后(即在加载和卸载库之后),您运行“pmap”以检查在“测试”中加载了哪些库,它会告诉您 libtest.so 仍然存在!现在,尽管 dlclose() 有一个有效的返回,并且没有合理的方式使引用计数在此之前超过 1(这可以通过尝试第二个 dlclose() 来验证 - 它会给出一个错误返回,说明它已经关闭)。

因此,要么 Linux 从不 卸载 dlopen() ed 库(与文档相矛盾),要么 'pmap' 是错误的。如果是后者,有没有更可靠的方法来判断一个库是否还在加载?

【问题讨论】:

    标签: c++ linux plugins g++ dlopen


    【解决方案1】:

    我在下面的程序中观察到的和你不同:

    // file soq.c
    #include <dlfcn.h>
    #include <iostream>
    #include <cstdio>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    using namespace std;
    int main(int argc, char** argv)
    {
      char cmd[60];
      snprintf(cmd, sizeof(cmd), "pmap %d", getpid());
        if (argc > 1)
        {
            void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL);
            if (!h)
            {
                cerr << "ERROR: " << dlerror() << endl;
                return 1;
            }
        cerr << "after dlopen " << argv[1] << endl;
        system(cmd);
            cin.get();
            if (dlclose(h))
            {
                cerr << "ERROR: " << dlerror() << endl;
                return 2;
            }
            cin.get();
        cerr << "after close " << argv[1] << endl;
        system(cmd);
        }
        return 0;
    }
    

    正如预期的那样,我得到了:

    % ./soq ./libempty.so
    ./soq ./libempty.so
    after dlopen ./libempty.so
    5276:   ./soq ./libempty.so
    0000000000400000      8K r-x--  /home/basile/tmp/soq
    0000000000601000      4K rw---  /home/basile/tmp/soq
    0000000001b4d000    132K rw---    [ anon ]
    00007f1dbfd01000      4K r-x--  /home/basile/tmp/libempty.so
    00007f1dbfd02000   2044K -----  /home/basile/tmp/libempty.so
    00007f1dbff01000      4K rw---  /home/basile/tmp/libempty.so
    00007f1dbff02000   1524K r-x--  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc007f000   2048K -----  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc027f000     16K r----  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc0283000      4K rw---  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc0284000     20K rw---    [ anon ]
    00007f1dc0289000     84K r-x--  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc029e000   2048K -----  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc049e000      4K rw---  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc049f000    516K r-x--  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0520000   2044K -----  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc071f000      4K r----  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0720000      4K rw---  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0721000    928K r-x--  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0809000   2048K -----  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a09000     32K r----  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a11000      8K rw---  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a13000     84K rw---    [ anon ]
    00007f1dc0a28000      8K r-x--  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0a2a000   2048K -----  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2a000      4K r----  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2b000      4K rw---  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2c000    128K r-x--  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e1c000     20K rw---    [ anon ]
    00007f1dc0e49000      8K rw---    [ anon ]
    00007f1dc0e4b000      4K r----  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e4c000      4K rw---  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e4d000      4K rw---    [ anon ]
    00007fff076c3000    132K rw---    [ stack ]
    00007fff077b4000      4K r-x--    [ anon ]
    ffffffffff600000      4K r-x--    [ anon ]
     total            15984K
    
    
    
    
    after close ./libempty.so
    5276:   ./soq ./libempty.so
    0000000000400000      8K r-x--  /home/basile/tmp/soq
    0000000000601000      4K rw---  /home/basile/tmp/soq
    0000000001b4d000    132K rw---    [ anon ]
    00007f1dbff02000   1524K r-x--  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc007f000   2048K -----  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc027f000     16K r----  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc0283000      4K rw---  /lib/x86_64-linux-gnu/libc-2.13.so
    00007f1dc0284000     20K rw---    [ anon ]
    00007f1dc0289000     84K r-x--  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc029e000   2048K -----  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc049e000      4K rw---  /lib/x86_64-linux-gnu/libgcc_s.so.1
    00007f1dc049f000    516K r-x--  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0520000   2044K -----  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc071f000      4K r----  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0720000      4K rw---  /lib/x86_64-linux-gnu/libm-2.13.so
    00007f1dc0721000    928K r-x--  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0809000   2048K -----  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a09000     32K r----  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a11000      8K rw---  /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17
    00007f1dc0a13000     84K rw---    [ anon ]
    00007f1dc0a28000      8K r-x--  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0a2a000   2048K -----  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2a000      4K r----  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2b000      4K rw---  /lib/x86_64-linux-gnu/libdl-2.13.so
    00007f1dc0c2c000    128K r-x--  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e1c000     20K rw---    [ anon ]
    00007f1dc0e48000     12K rw---    [ anon ]
    00007f1dc0e4b000      4K r----  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e4c000      4K rw---  /lib/x86_64-linux-gnu/ld-2.13.so
    00007f1dc0e4d000      4K rw---    [ anon ]
    00007fff076c3000    132K rw---    [ stack ]
    00007fff077b4000      4K r-x--    [ anon ]
    ffffffffff600000      4K r-x--    [ anon ]
     total            13936K 
    

    所以你确实错误地运行了你的pmap

    顺便说一句,您可以在实践中避免任何dlclose-ing,正如我的manydl.c 示例所示。在实践中,不打扰dlclose-ing 仅意味着很小的地址空间泄漏,实际上并没有什么大不了的。 (您可以dlopen 近百万个不同的共享对象而不会受到太大伤害)。

    要知道何时卸载共享对象,请使用 dlclose-d 插件的“析构函数”(例如 C++ 中静态数据的析构函数,或 C 中的 attribute((destructor))代码),因为它们是从卸载 dlclose 内部调用的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-18
      • 2015-01-05
      • 1970-01-01
      相关资源
      最近更新 更多