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