如何处理用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构build和复制在/插件。 执行正常工作,直到我覆盖它

 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 

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

所以如果你在构建过程中使用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)你的共享库,同时仍然使用它。

因此,不要在现有的共享库inode上覆盖字节。 做任何必要的事情,确保在你的插件构建过程中创建一个新的共享库inode

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

顺便说一下,真正的问题与dlopen无关,而是与POSIX系统上的文件描述符 (即已打开的inode)的性质有关(在这些系统上有几个进程可以读写同一文件;用户或系统管理员或工具开发人员)应该避免破坏破坏)。

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

实际上,安装插件的用户或系统管理员应确保为其创建了原始inode,或者没有进程正在使用该插件(在安装之前)。 这是他的责任(并且是整个系统问题)。 所以你真的需要教育你的用户或者系统管理员,并且记录下这个问题,例如,在安装插件的时候,建议使用install(1)和/或像包管理器这样的锁定工具。

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