复制动态库时dlclose崩溃

时间:2011-10-11 18:49:18

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

我有一个有趣的问题似乎没有被我在互联网上的研究所解决。 我正在尝试使用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)时会出现问题)。如果我使用move命令(mv),则不会发生错误。使用cp或mv有什么区别?有没有办法解决这个问题或使用cp来做到这一点?

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

提前致谢。

2 个答案:

答案 0 :(得分:5)

与此问题相关的cpmv之间的差异如下:

  1. cp打开目标文件并将新内容写入其中。因此,用新内容替换旧内容
  2. mv不会触及原始文件的内容。相反,它使目录条目指向新文件。
  3. 这结果很重要。在应用程序运行时,操作系统会保留对可执行文件和共享对象的打开句柄。当需要查阅其中一个文件时,它会使用相关句柄来访问文件的内容。

    1. 如果您使用过cp,则内容现已损坏,因此可能发生任何事情(段错误很可能会产生结果)。
    2. 如果您使用过mv,则打开的文件句柄仍会引用原始文件,即使不再有目录条目,该文件也会继续存在于磁盘上。
    3. 如果您已使用mv替换共享对象,则应该能够dlclose旧的和dlopen新的共享对象。但是,这不是我已经完成或建议的事情。

答案 1 :(得分:-1)

试试这个:

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