Exception in dynamischer Bibliothek werfen



  • Ich möchte eine Exception in einer Funktion werfen, die in einer dynamischen Bibliothek definiert ist. Die Exception jedoch ist im Hauptprogramm definiert, das das Exception-Objekt dann auch fangen soll. Allerdings fängt er es anscheinend nur, wenn ich direkt im Hauptprogramm werfe; wenn ich es in der Bibliothek tue, fällt die Exception bis ganz nach oben durch. Warum macht das einen Unterschied, kann das das nicht machen?

    Exception.h:

    #include <string>
    
    // Simple Exception-Klasse
    class Exception {
    	std::string msg;
      public:
    	Exception(std::string);
    	std::string getMessage();
    };
    

    Exception.cpp:

    #include <string>
    
    using std::string;
    
    #include "Exception.h"
    
    Exception::Exception(string m) : msg(m) {}
    
    string Exception::getMessage() {
    	return msg;
    }
    

    library.cpp:

    #include <string>
    
    using std::string;
    
    #include "Exception.h"
    
    // Was ich bekomme: Callback-Constructor-Typ
    typedef Exception* (*ctor_t)(string);
    
    extern "C" {
    	void init(ctor_t ctor) {
    		throw ctor("foo");   // wirf eine neue Exception
    	}
    }
    

    program.cpp:

    #include <iostream>
    #include <string>
    #include <dlfcn.h>
    
    using std::cout;
    using std::endl;
    using std::string;
    
    #include "Exception.h"
    
    // Ich muss das Objekt ja im Hauptprogramm erstellen...
    Exception* ctor(string msg) {
    	return new Exception(msg);
    }
    
    // Was ich gebe: Callback-Constructor-Typ
    typedef Exception* (*ctor_t)(string);
    // Was ich aus der Bibliothek lade
    typedef void (*init_t)(ctor_t);
    
    int main() {
    	// OK, Bibliothek laden, das klappt ja alles
    	void* lib = dlopen("./library.so", RTLD_LAZY);
    	init_t init = (init_t)dlsym(lib, "init");
    	// Jetzt wird's witzig, die Funktion aus der Bibliothek aufrufen:
    	try {
    		init(ctor);
    	}
    	catch(Exception* e) {
    		// Aber dummerweise komme ich nie hier an
    		cout << "Exception: " << e->getMessage() << endl;
    	}
    	return 0;
    }
    

    Funktionert aber nicht:

    $ g++ -fPIC -c library.cpp
    $ g++ -shared -Wl,-soname,library.so -olibrary.so library.o
    $ g++ Exception.cpp program.cpp -ldl
    $ ./a.out
    terminate called after throwing an instance of 'Exception*'
    zsh: abort      ./a.out
    

    PS: Das Problem scheint tatsächlich zu sein, dass er das, was da fliegt, nicht als Exception* erkennt. Wenn ich das Ding vor dem Werfen nach int caste und nach dem Fangen wieder zurück, funktionert es einwandfrei...



  • Hallo,
    der C++ Standard schreibt nicht vor, ob das Werfen/Fangen von Exceptions über Bibliotheksgrenzen hinasus funktioniert, sowas ist im höchsten maße Compiler-abhängig. Im Allgemeinen funktioniert das nicht, da sich der Exception-Mechanismus von Compiler zu Compiler und von Runtime-Lib zu Runtime-Lib unterscheidet. Falls du wirklich diesen Weg beschreiten willst, wirst du ein passende Antwort auf deine Frage sich in der gcc-Doku finden.

    Gängige Praxis ist es aber, Exceptions nur lokal zu verwenden, sie also an Modulgrenzen zu fangen. Dort können sie z.B. dann auf Fehlercodes abgebildet werden.




Anmelden zum Antworten