我在我的程序中使用了一个通过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构建并在[...] / plugins中复制。执行工作正常,直到我覆盖它
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
}
答案 0 :(得分:3)
你的问题不清楚。
如果您有/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
)中的字节
因此,如果您在构建过程中使用/tmp/plugin.so
命令覆盖旧的mv /tmp/newplugin.so /tmp/plugin.so
,那么您最好在之前执行mv /tmp/plugin.so /tmp/plugin.so~
或rm /tmp/plugin.so
。< / p>
请注意,mmap(2)(由dlopen(3)内部调用)实际上正在处理打开的inode。见path_resolution(7)。因此,您可以unlink(2)使用共享库dlopen
- 编辑。
所以永远不要覆盖现有共享库 inode 中的字节;尽一切可能确保在插件构建过程中创建新鲜共享库 inode 。
阅读Advanced Linux Programming&amp; Drepper的How to Write a Shared Library
BTW,真正的问题与dlopen
无关,而与POSIX系统上file descriptors(即打开的inode)的性质无关(多个进程可以读取和写入相同的文件) ;用户或系统管理员 - 或工具开发者 - 应该避免破坏。)。
还可以使用pmap(1)(作为pmap 1234
)和/或cat /proc/1234/maps
来了解pid 1234 process的内存映射(即其virtual address space)。
实际上,安装插件的用户或系统管理员应确保为其创建原始inode,或者没有进程正在使用该插件(在安装之前)。这是他的责任(并且是一个完整的系统问题)。所以你真的需要教育你的用户或系统管理员,并记录问题,例如建议在安装插件时使用install(1)和/或锁定package managers等实用程序。
PS。在dlopen
之前复制私有副本中的共享对象可能会改善这种情况,但不能解决问题(如果共享对象源在复制期间得到更新会怎样?)。真正的错误在于构建过程,它会覆盖共享对象而不是写入&amp;创建一个原始的新inode。