【问题标题】:dlclose crashes when copying dynamic libraries复制动态库时 dlclose 崩溃
【发布时间】:2011-10-11 18:49:18
【问题描述】:

我有一个有趣的问题,我在互联网上的研究似乎没有解决这个问题。 我正在尝试使用 dlfcn.h 中的函数在我的 c++ 项目中动态加载库。问题是,当我尝试在运行时重新加载插件时(因为我对它们中的任何一个进行了更改),调用 dlclose() 时主程序崩溃(分段错误(核心转储))。 这是我重现错误的示例:

main.cpp:

#include    <iostream>
#include    <dlfcn.h>
#include    <time.h>
#include    "IPlugin.h"

int main( )
{
    void * lib_handle;
    char * error;

    while( true )
    {
        std::cout << "Updating the .so" << std::endl;

        lib_handle = dlopen( "./test1.so", RTLD_LAZY );
        if ( ! lib_handle ) 
        {
            std::cerr << dlerror( ) << std::endl;
            return 1;
        }

        create_t fn_create = ( create_t ) dlsym( lib_handle, "create" );

        if ( ( error = dlerror( ) ) != NULL )  
        {
            std::cerr << error << std::endl;
            return 1;
        }

        IPlugin * ik = fn_create( );
        ik->exec( );

        destroy_t fn_destroy = ( destroy_t ) dlsym( lib_handle, "destroy" );

        fn_destroy( ik );

        std::cout << "Waiting 5 seconds before unloading..." << std::endl;

        sleep( 5 );
        dlclose( lib_handle );
    }

    return 0;
}

IPlugin.h:

class IPlugin
{
public:
    IPlugin( ) { } 
    virtual ~IPlugin( ) { }
    virtual void exec( ) = 0;
};

typedef IPlugin * ( * create_t  )( );
typedef void ( * destroy_t  )( IPlugin * );

Test1.h:

#include    <iostream>
#include    "IPlugin.h"

class Test1 : public IPlugin
{
public:
    Test1( );
    virtual ~Test1( );

    void exec( );
};

Test1.cpp:

#include "Test1.h"

Test1::Test1( ) { }

Test1::~Test1( ) { }

void Test1::exec( )
{
    std::cout << "void Test1::exec( )" << std::endl;
}

extern "C"
IPlugin * create( )
{
    return new Test1( );
}

extern "C"
void destroy( IPlugin * plugin )
{
    if( plugin != NULL )
    {
        delete plugin;
    }
}

编译:

g++ main.cpp -o main -ldl
g++ -shared -fPIC Test1.cpp -o plugin/test1.so

例如,当我更改 Test1::exec 方法上的某些内容(更改要打印的字符串或注释行)并且在主程序休眠时,我将新的 test1.so 复制到主运行目录(cp )。如果我使用移动命令 (mv),则不会发生错误。使用 cp 或 mv 有什么区别?有没有办法解决这个问题或使用 cp 来解决这个问题?

我正在使用带有 g++ (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4) 的 Fedora 14。

提前致谢。

【问题讨论】:

  • 我想这是因为RTLD_LAZY,试试RTLD_NOW
  • 优秀的问题组合。要是所有新成员都那么擅长写高质量的问题就好了!
  • 我已经使用 RTLD_NOW 和提到的两个选项(RTLD_LAZY 和 RTLD_NOW)与 RTLD_GLOBAL 和 RTLD_LOCAL 进行了 ORed 测试。结果保持不变...

标签: c++ g++ dynamic-linking


【解决方案1】:

与本题相关的cpmv的区别如下:

  1. cp 打开目标文件并将新内容写入其中。因此,它用新内容替换旧内容
  2. mv 不会触及原始文件的内容。相反,它使目录入口指向新文件。

事实证明这很重要。在应用程序运行时,操作系统会保留可执行文件和共享对象的打开句柄。当它需要查阅这些文件之一时,它会使用相关句柄来访问文件的内容。

  1. 如果您使用过cp,则内容现在已损坏,因此任何事情都可能发生(很可能会出现段错误)。
  2. 如果您使用过mv,则打开的文件句柄仍然引用原始文件,即使不再有目录条目,该文件仍会继续存在于磁盘上。

如果您使用mv 替换共享对象,您应该可以dlclose 旧的和dlopen 新的。但是,这不是我做过或不会推荐的事情。

【讨论】:

  • 实现这一点的最佳方法通常是使用install 命令。
【解决方案2】:

试试这个:

extern "C"
void destroy( IPlugin * plugin )
{
    if( plugin != NULL && dynamic_cast<Test1*>(plugin))
    {
        delete static_cast<Test1*>(plugin);
    }
}

【讨论】:

  • 这应该是评论,而不是答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
相关资源
最近更新 更多