开发者

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

开发者 https://www.devze.com 2022-12-11 18:33 出处:网络
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.

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.

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

Edit 2: I throw custom exceptions w开发者_如何转开发ith 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 works in Windows (to catch my exceptions) but there I dont use dlopen of course.

Edit 3: myLib1.so is dynamically linked.


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

精彩评论

暂无评论...
验证码 换一张
取 消