簡體   English   中英

如何處理使用dlopen()打開的已更改庫

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM