繁体   English   中英

如何处理使用dlopen()打开的已更改库

[英]How to handle a changed Library opened with dlopen()

我在程序中使用共享对象,该对象通过dlopen()加载。 当我用mv debug/newLibrary.so plugin/usedLibrary.so覆盖库时,一旦尝试与加载的库进行交互,我的程序就会崩溃。 我什至不能使用dlclose(),这使我得到了SIGSEV。

处理这种情况的最佳方法是什么?

操作系统是Linux

编辑:实际代码

void DynamicallyLoadedLibrary::loadLibrary() {
    // ModificationTime updaten
    lastModificationTime = modificationTime();

    // Library laden
    libraryHandle = dlopen(path.c_str(), RTLD_NOW);

    if (!libraryHandle) { // Library gefunden?
        throw DynamicLibraryException("Dynamic Library not found: " + path + "\n" + dlerror());
    }

    // Funktion laden
    externalFunction = (dll_function) dlsym(libraryHandle, "run");

    char *error;
    if ((error = dlerror()) != NULL) { // Funktion gefunden?
        throw DynamicLibraryException("Dynamic Library not found: run()\n" + string(error));
    }
}

void DynamicallyLoadedLibrary::close() {
    if (libraryHandle != nullptr) {
        cout << "DLL/close(): " << dlclose(libraryHandle) << endl; // DEBUG
        libraryHandle = nullptr;
        externalFunction = nullptr;
    }
}

void DynamicallyLoadedLibrary::operator()(vector<shared_ptr<ServerData>> &data) {
    // Wenn Datei sich geaendert hat, neu laden
    if (fileChanged()) {
        close();
        loadLibrary();
    }

    externalFunction(data);
}

编辑2:库(UA_String来自open62541 )它仅使用eclipse构建并复制到[/]插件中。 执行正常,直到我覆盖它

extern "C" void run(vector<shared_ptr<ServerData>> &data) {
    cout << "++++ OPC_WORKING_PACKAGE EXTERN ++++" << endl; // XXX
    for (unsigned int i = 0; i < data.size(); i++){
        UA_String *uaString = (UA_String*) data[i]->dataReference();
        cout << string((char*) uaString->data, uaString->length) << endl;
    }
    cout << "---- OPC_WORKING_PACKAGE EXTERN ----" << endl; // XXX
}

您的问题不清楚。

如果您有一些/tmp/plugin.so而您

void* dl = dlopen("/tmp/plugin.so", TRL_NOW);

后来(以相同的过程)

rename("/tmp/plugin.so", "/tmp/oldplugin.so")

(甚至是unlink("/tmp/plugin.so"); ...),您应该能够dlclose(dl);

但是,如果您的构建过程正在建立一个新的过程,例如您有一些make /tmp/plugin.so目标,那么您确实应该执行

 mv /tmp/plugin.so /tmp/plugin.so~ 

甚至

 rm /tmp/plugin.so

共享库链接 ,例如前

gcc -shared -Wall -O /tmp/plugin*.pic.o -o /tmp/plugin.so

换句话说,请确保您的构建过程不会覆盖同一 inode (原始/tmp/plugin.so )中的字节

因此,如果在构建过程中使用某些mv /tmp/newplugin.so /tmp/plugin.so命令覆盖了旧的/tmp/plugin.so ,则最好执行mv /tmp/plugin.so /tmp/plugin.so~rm /tmp/plugin.so就在之前。

请注意, mmap(2) (由dlopen(3)内部调用)实际上在打开的inode上起作用。 参见path_resolution(7) 因此,您可以取消链接(2)您的共享库,同时对其进行dlopen -ed。

因此,切勿覆盖现有共享库inode中的字节; 做所有必要的事情以确保在插件构建过程中创建一个新的共享库inode

阅读高级Linux编程和Drepper的如何编写共享库的方法

顺便说一句,真正的问题与dlopen无关,而与POSIX系统上的文件描述符 (即打开的inode)的性质有关(在该系统上,多个进程可以读取和写入同一文件;用户或sysadmin-或工具开发人员-应该避免破坏。)。

也可以使用pmap(1) (如pmap 1234 )和/或cat /proc/1234/maps来了解pid 1234 进程的内存映射(即其虚拟地址空间 )。

实际上,安装插件的用户或系统管理员应确保为其创建了一个原始的inode,或者没有进程在使用该插件(安装前)。 这是他的责任(并且是整个系统的问题)。 因此,您确实需要教育您的用户或sysadmin,并记录该问题,例如,建议在安装插件时建议使用install(1)和/或锁定实用程序,如程序包管理器

PS。 dlopen之前在私有副本中复制共享对象可能会改善这种情况,但不能解决问题(如果共享对象源在复制期间得到更新,该怎么办?)。 真正的错误在于构建过程中,该过程将覆盖共享对象,而不是编写和创建原始的新inode。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM