Nar*_*ase 2 c++ linux dll 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);
}
Run Code Online (Sandbox Code Playgroud)
编辑 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
}
Run Code Online (Sandbox Code Playgroud)
你的问题不清楚。
如果你有一些/tmp/plugin.so并且你这样做了
void* dl = dlopen("/tmp/plugin.so", TRL_NOW);
Run Code Online (Sandbox Code Playgroud)
后来(在同一过程中)一些
rename("/tmp/plugin.so", "/tmp/oldplugin.so")
Run Code Online (Sandbox Code Playgroud)
(甚至unlink("/tmp/plugin.so");......)你应该能够dlclose(dl);
但是,如果您的构建过程正在创建一个新的,例如您有一些make /tmp/plugin.so目标,那么您确实应该做一个
mv /tmp/plugin.so /tmp/plugin.so~
Run Code Online (Sandbox Code Playgroud)
甚至
rm /tmp/plugin.so
Run Code Online (Sandbox Code Playgroud)
在链接共享库之前,例如之前
gcc -shared -Wall -O /tmp/plugin*.pic.o -o /tmp/plugin.so
Run Code Online (Sandbox Code Playgroud)
换句话说,确保您的构建过程不会覆盖(原始)同一 inode中的字节/tmp/plugin.so
/tmp/plugin.so因此,如果您在构建过程中使用某些命令覆盖旧mv /tmp/newplugin.so /tmp/plugin.so命令,您最好在之前执行 amv /tmp/plugin.so /tmp/plugin.so~或 a 。rm /tmp/plugin.so
请注意,mmap(2) (由dlopen(3)在内部调用)实际上是在打开的 inode 上工作。请参阅path_resolution(7)。因此,您可以取消链接(2)您的共享库,同时仍然保留它dlopen。
因此,切勿覆盖现有共享库inode中的字节;尽一切必要确保在插件构建过程中创建一个新的共享库索引节点。
阅读高级 Linux 编程和 Drepper 的《如何编写共享库》
顺便说一句,真正的问题与POSIX 系统上的文件描述符(即打开的索引节点)dlopen的性质无关(多个进程可以读写同一个文件;用户或系统管理员或工具开发人员)应该避免造成严重破坏。)。
还可以使用pmap(1)(如pmap 1234)和/或cat /proc/1234/maps了解pid 1234进程的内存映射(即其虚拟地址空间)。
实际上,安装插件的用户或系统管理员应确保为其创建原始 inode,或者没有进程正在使用该插件(在安装之前)。这是他的责任(并且是整个系统问题)。因此,您确实需要教育您的用户或系统管理员,并记录问题,例如在安装插件时建议使用install(1)和/或锁定实用程序(如包管理器)。
附言。之前复制共享对象的私有副本dlopen可能会改善情况,但不能解决问题(如果共享对象源在复制过程中更新怎么办?)。真正的错误是在构建过程中,它覆盖了共享对象,而不是编写和创建原始的新索引节点。