简体   繁体   中英

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

When i use dlopen to dynamically load a library it seems i can not catch exceptions thrown by that library. As i understand it it's because dlopen is a C function.

Is there another way to dynamically load a library that makes it possible to catch exceptions thrown by the lib in GCC?

In Windows you can use LoadLibrary but for Linux i have only found dlopen but when using dlopen i can not catch exceptions.

: I have tried void* handle = dlopen("myLib.so", RTLD_NOW | RTLD_GLOBAL);:我试过 void* handle = dlopen("myLib.so", RTLD_NOW | RTLD_GLOBAL); and I still cant catch exceptions thrown by myLib.so

: I throw custom exceptions with its own namespace. :我用自己的命名空间抛出自定义异常。 I want to be able to catch these exceptions outside the library. I want to be able to compile on different compilers, for example GCC 3.2 and GCC 4.1.

In myLib2.so i throw exceptions, one example:

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

In myLib1.so I want to catch that exception:

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 dynamically loads myLib2.so with:

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

This (to catch my exceptions) but there I dont use dlopen of course. (以捕获我的异常),但我当然不使用 dlopen。

: myLib1.so is dynamically linked. :myLib1.so 是动态链接的。

You need to specify RTLD_GLOBAL flag to dlopen. This will allow correct weak symbol binding, so each typeinfo symbol for exception object will point at the same place, which is needed by exception processing ABI code.

This depends on the version of GCC you are using.
First of all, make sure you compile everything with "-fPIC" and link with the "-rdynamic" flag.
RTLD_NOW flag is still needed.

The set up is unclear, so I improvised

There are multiple descriptions of your set up that are slightly conflicting. So, my description may not match up with what you have, but hopefully it addresses your question.

The setup I used

The stub implementations of the libs are included at the bottom of this answer, as is the Makefile . But the basic organization is:

  • myLib.so has the class with a method that will throw an exception
  • myLib1.so has the function that loads myLib.so and invokes the method

I then attempted various versions of the myTest.cpp to see what would work.

RTLD_GLOBAL does not work on myLib1.so

Invoking dlopen("./myLib1.so", RTLD_GLOBAL | RTLD_NOW) is just like trying to link it into the executable. My attempt to use the above call resulted in a NULL handler being returned. When I attempted to link it directly into the executable instead, I got a linker error.

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

This is an explanation as to why using RTLD_GLOBAL failed. It could not resolve the symbols that are defined in myLib.so . I could fix this by including myLib.so in the link line too, but then there is no dynamic loading happening at all.

RTLD_LAZY can be made to work

If you are not insistent on being able to invoke the code directly, you can use RTLD_LAZY on myLib1.so instead. This would require d dlsym() call to find the entry point function to call. But that lookup will trigger a lazy symbol resolution mechanism that causes the inner code to succeed.

Below is the working myTest.cpp file I used.

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

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

The source files

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(); }
}

myLib1.h

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

void foo ();

#ifdef __cplusplus
}
#endif

myLib1.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);
}

Makefile

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 $@

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM