簡體   English   中英

如何在 GCC C++ 中捕獲從庫中拋出的異常?

[英]How to catch exception thrown from library in GCC C++?

當我使用 dlopen 動態加載庫時,似乎我無法捕獲該庫引發的異常。 據我了解,這是因為 dlopen 是一個 C 函數。

是否有另一種動態加載庫的方法,可以捕獲 GCC 中的庫引發的異常?

在 Windows 中,您可以使用 LoadLibrary,但對於 Linux,我只找到 dlopen,但在使用 dlopen 時,我無法捕獲異常。

編輯:我試過 void* handle = dlopen("myLib.so", RTLD_NOW | RTLD_GLOBAL); 而且我仍然無法捕獲 myLib.so 引發的異常

編輯 2 :我用自己的命名空間拋出自定義異常。 我希望能夠在庫之外捕獲這些異常。 我希望能夠在不同的編譯器上編譯,例如 GCC 3.2 和 GCC 4.1。

在 myLib2.so 我拋出異常,一個例子:

namespace MyNamespace {  
    void MyClass::function1() throw(Exception1) {  
        throw Exception1("Error message");  
    } 
}

在 myLib1.so 中,我想捕獲該異常:

std::auto_ptr <MyNamespace::MyClass> obj = MyNamespace::getClass();
try {  
    obj->function1();  
} catch (MyNamespace::Exception1& e) {  
    std::cout << e.what();  //This is not caught for some reason.  
}

mylib1.so 動態加載 myLib2.so:

void* handle = dlopen("myLib2.so", RTLDNOW | RTLDGLOBAL);

適用於 Windows (以捕獲我的異常),但我當然不使用 dlopen。

編輯 3 :myLib1.so 是動態鏈接的。

您需要為 dlopen 指定 RTLD_GLOBAL 標志。 這將允許正確的弱符號綁定,因此異常對象的每個 typeinfo 符號將指向同一個位置,這是異常處理 ABI 代碼所需要的。

這取決於您使用的 GCC 版本。
首先,確保使用“-fPIC”編譯所有內容並使用“-rdynamic”標志鏈接。
仍然需要 RTLD_NOW 標志。

設置不清楚,所以我即興發揮

您的設置有多個描述略有沖突。 因此,我的描述可能與您所擁有的不符,但希望它能解決您的問題。

我使用的設置

庫的存根實現包含在此答案的底部,就像Makefile一樣。 但基本組織是:

  • myLib.so的類有一個會拋出異常的方法
  • myLib1.so具有加載myLib.so並調用方法的函數

然后我嘗試了各種版本的myTest.cpp來看看有什么用。

RTLD_GLOBAL不適用於myLib1.so

調用dlopen("./myLib1.so", RTLD_GLOBAL | RTLD_NOW)就像嘗試將其鏈接到可執行文件中一樣。 我嘗試使用上述調用導致返回NULL處理程序。 當我嘗試將其直接鏈接到可執行文件時,出現鏈接器錯誤。

g++ -g myTest.cpp ./myLib1.so -ldl -o myTest
./myLib1.so: undefined reference to `MyNamespace::MyClass::function1()'
./myLib1.so: undefined reference to `MyNamespace::getClass()'
collect2: error: ld returned 1 exit status

這是對使用RTLD_GLOBAL失敗的原因的解釋。 它無法解析myLib.so中定義的符號。 我也可以通過在鏈接行中包含myLib.so來解決這個問題,但是根本不會發生動態加載。

RTLD_LAZY可以工作

如果您不堅持能夠直接調用代碼,則可以在myLib1.so上使用RTLD_LAZY 這將需要 d dlsym()調用來找到要調用的入口點函數。 但是該查找將觸發導致內部代碼成功的惰性符號解析機制。

下面是我使用的工作myTest.cpp文件。

#include "myLib1.h"
#include <dlfcn.h>

int main () {
    void * h = dlopen("./myLib1.so", RTLD_LAZY);
    void (*foo)() = (void(*)())dlsym(h, "foo");
    foo();
    dlclose(h);
}

源文件

myLib.h

#pragma once

namespace MyNamespace {

    struct Exception1 {
        const char *what_;
        Exception1(const char *what) : what_(what) {}
        const char * what () const { return what_; }
    };

    struct MyClass {
        friend MyClass * MyNamespace::getClass ();
        void function1 () throw(Exception1);
    private:
        MyClass () {}
    };

    MyClass * getClass ();

}

myLib.cpp

#include "myLib.h"

namespace MyNamespace {
    void MyClass::function1() throw(Exception1) {
        throw Exception1("Error message");
    }

    MyClass * getClass () { return new MyClass(); }
}

我的Lib1.h

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

void foo ();

#ifdef __cplusplus
}
#endif

我的Lib1.cpp

#include "myLib1.h"
#include "myLib.h"
#include <iostream>
#include <dlfcn.h>

void foo () {
    void *h = dlopen("./myLib.so", RTLD_GLOBAL | RTLD_NOW);
    MyNamespace::MyClass *p = MyNamespace::getClass();
    try {
        p->function1();
    } catch (MyNamespace::Exception1 e) {
        std::cout << e.what() << std::endl;
    }
    delete p;
    dlclose(h);
}

生成文件

all : myLib.so myLib1.so myTest
clean :
        rm -f *.o *.so myTest

%.so : %.o
        g++ -shared -o $@ $<

%.o : %.cpp
        g++ -std=c++03 -W -Wall -Werror -fPIC -rdynamic -O3 -g -c $<

myLib.so : myLib.h
myLib1.so : myLib1.h myLib.h

myTest : myTest.cpp myLib1.h
        g++ -g $< $(MYLIB) -ldl -o $@

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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