[英]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.