简体   繁体   English

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

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

I'm using a shared object in my program which is loaded via dlopen(). 我在程序中使用共享对象,该对象通过dlopen()加载。 When I overwrite the library with mv debug/newLibrary.so plugin/usedLibrary.so my program crashes as soon as it tries to interact with the loaded library. 当我用mv debug/newLibrary.so plugin/usedLibrary.so覆盖库时,一旦尝试与加载的库进行交互,我的程序就会崩溃。 I cant even use dlclose(), this gets me a SIGSEV. 我什至不能使用dlclose(),这使我得到了SIGSEV。

What is the best way to handle with this situations? 处理这种情况的最佳方法是什么?

OS is Linux 操作系统是Linux

Edit: actual code 编辑:实际代码

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);
}

Edit 2: The Library (UA_String is from open62541 ) Its simply build with eclipse and copied in [...]/plugins. 编辑2:库(UA_String来自open62541 )它仅使用eclipse构建并复制到[/]插件中。 Execution works fine until I overwrite it 执行正常,直到我覆盖它

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
}

Your question is unclear. 您的问题不清楚。

If you have some /tmp/plugin.so and you do 如果您有一些/tmp/plugin.so而您

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

and later (in the same process) some 后来(以相同的过程)

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

(or even unlink("/tmp/plugin.so"); ...) you should be able to dlclose(dl); (甚至是unlink("/tmp/plugin.so"); ...),您应该能够dlclose(dl);

However, if your build process is making a new one, eg you have some make /tmp/plugin.so target, then you really should do a 但是,如果您的构建过程正在建立一个新的过程,例如您有一些make /tmp/plugin.so目标,那么您确实应该执行

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

or even 甚至

 rm /tmp/plugin.so

before linking the shared library, eg before 共享库链接 ,例如前

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

In other words, be sure that your build procedure is not overwriting bytes in the same inode (of the original /tmp/plugin.so ) 换句话说,请确保您的构建过程不会覆盖同一 inode (原始/tmp/plugin.so )中的字节

So if you overwrite your old /tmp/plugin.so with some mv /tmp/newplugin.so /tmp/plugin.so command in your build process you'll better do a mv /tmp/plugin.so /tmp/plugin.so~ or a rm /tmp/plugin.so just before. 因此,如果在构建过程中使用某些mv /tmp/newplugin.so /tmp/plugin.so命令覆盖了旧的/tmp/plugin.so ,则最好执行mv /tmp/plugin.so /tmp/plugin.so~rm /tmp/plugin.so就在之前。

Notice that mmap(2) (internally invoked by dlopen(3) ) is actually working on opened inodes. 请注意, mmap(2) (由dlopen(3)内部调用)实际上在打开的inode上起作用。 See path_resolution(7) . 参见path_resolution(7) So you could unlink(2) your shared library while still having it dlopen -ed. 因此,您可以取消链接(2)您的共享库,同时对其进行dlopen -ed。

So never overwrite bytes in an existing shared library inode ; 因此,切勿覆盖现有共享库inode中的字节; do whatever is necessary to be sure to create a fresh shared library inode in your plugin build procedure. 做所有必要的事情以确保在插件构建过程中创建一个新的共享库inode

Read Advanced Linux Programming & Drepper's How to Write a Shared Library 阅读高级Linux编程和Drepper的如何编写共享库的方法

BTW, the real issue is not related to dlopen but to the nature of file descriptors (that is, of opened inodes) on POSIX systems (on which several processes can read and write the same file; the user or sysadmin -or tool developer- is supposed to avoid breaking havoc.). 顺便说一句,真正的问题与dlopen无关,而与POSIX系统上的文件描述符 (即打开的inode)的性质有关(在该系统上,多个进程可以读取和写入同一文件;用户或sysadmin-或工具开发人员-应该避免破坏。)。

Use also pmap(1) (as pmap 1234 ) and/or cat /proc/1234/maps to understand the memory mapping of process of pid 1234 (ie its virtual address space ). 也可以使用pmap(1) (如pmap 1234 )和/或cat /proc/1234/maps来了解pid 1234 进程的内存映射(即其虚拟地址空间 )。

In practice, the user or sysadmin installing a plugin should ensure that a pristine inode is created for it, or that no process is using that plugin (before installation). 实际上,安装插件的用户或系统管理员应确保为其创建了一个原始的inode,或者没有进程在使用该插件(安装前)。 It is his responsibility (and is a whole system issue). 这是他的责任(并且是整个系统的问题)。 So you really need to educate your user or sysadmin, and document the issue, eg by suggesting the use of install(1) and/or locking utilities like package managers when installing plugins. 因此,您确实需要教育您的用户或sysadmin,并记录该问题,例如,建议在安装插件时建议使用install(1)和/或锁定实用程序,如程序包管理器

PS. PS。 Copying in a private copy the shared object before dlopen might improve the situation, but does not solve the issue (what if the shared object source gets updated during the copy?). dlopen之前在私有副本中复制共享对象可能会改善这种情况,但不能解决问题(如果共享对象源在复制期间得到更新,该怎么办?)。 The real bug is in the build process which overwrites a shared object instead of writing & creating a pristine new inode. 真正的错误在于构建过程中,该过程将覆盖共享对象,而不是编写和创建原始的新inode。

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

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