Programmabsturz beim Beenden



  • Hallo Zusammen!

    Ich bin gerade dabei meinen eigenen ClassLoader zu basteln (ich weiß, dass gibt es fertig, aber um meine C++-Fähigkeiten zu verbessern will ich es selbst machen). Dafür habe ich bis jetzt folgenden Code produziert (soweit zsuammengekürzt, dass der Fehler noch kommt):

    child.hpp

    #ifndef CHILD_HPP_
    #define CHILD_HPP_
    
    #include <iostream>
    #include <map>
    
    struct object_factories{};
    
    template <typename classtype> struct object_factory : public object_factories {
    
    	static classtype* new_instance() { return new classtype; }
    	static void destroy_instance(classtype *&ptr) { delete ptr; ptr = NULL; }
    
    };
    
    class instantiator {
    
    	public:
    
    		typedef std::map<const char*, object_factories*> object_factory_map;
    
    		static void addClass(const char* className, object_factories* object_factory_ptr) { 
    			std::cout << "Registriere Klasse '" << className << "' (Factory-Map: " << &factory_map() << ")" << std::endl;
     			factory_map().insert(std::pair<const char*, object_factories*>(className, object_factory_ptr));
    		}
    
    		static void __attribute__ ((destructor)) destroy_factories() {
    			for(object_factory_map::const_iterator i = factory_map().begin(); i != factory_map().end(); ++i) {
    				std::cout << "Zerstöre Faktorie für Klasse '" << i->first << "' (Factory-Map: " << &factory_map() << ")" << std::endl;
    				object_factories *ptr = i->second; delete ptr;
    			}
    			factory_map().clear();
    		}
    
    	private:
    
    		inline static object_factory_map& factory_map() {
    			static object_factory_map fac_map;
    			return fac_map;
    		}
    
    };
    
    class Child {
    
    		Child();
    		~Child();
    
    };
    
    // Registriere Klasse Child
    namespace {
    
    	template <typename Context> struct cl_reg_context { static bool placeholder; };
    	template <typename Context> bool cl_reg_context<Context>::placeholder = false;
    
    	template<> bool cl_reg_context<Child>::placeholder=(instantiator::addClass("Child", new object_factory<Child>), true);
    
    }
    
    #endif
    

    child.cpp:

    #include <iostream>
    #include "child.hpp"
    
    Child::Child() {}
    Child::~Child() {}
    

    main.cpp:

    #include <iostream>
    #include <dlfcn.h>
    #include "child.hpp"
    
    int main() {
    
    	void *handle = dlopen("./Child.so", RTLD_LAZY);
    	dlclose(handle);
    
    	std::cout << "Ping" << std::endl;
    
    	return 0;
    }
    

    GNUmakefile

    all:
    	g++ -g -Wall -shared -o Child.so child.cpp
    	g++ -g -Wall -ldl main.cpp -o cl
    
    clean:
    	rm -f *.so cl cl.exe
    

    Wenn ich das ganze nun übersetzte und Ausführe kommt folgende Ausgabe:

    Registriere Klasse 'Child' (Factory-Map: 0x443168)
    Registriere Klasse 'Child' (Factory-Map: 0x18733168)
    Zerstöre Faktorie für Klasse 'Child' (Factory-Map: 0x18733168)
    Ping
          5 [main] cl 3084 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack)
    Segmentation fault (core dumped)
    

    Also nochmal zum Mitdenken: Es gibt letztlich zwei Factory-Maps. Eine in der Exe-Datei und eine in der Child.so. Wenn das Programm startet registriert sich die Klasse Child in der Factory-Map der Exe-Datei. Dann Lade ich die Child.so und dabei registriert sich die Klasse Child nochmal in der Factory-Map der Child.so-Datei. Dann schließe ich die Child.so wieder und destroy_factories() wird in der Child.so sauber aufgerufen und verrichtet wie es soll seinen Dienst. Zurück in der main()-Funktion kommt auch noch das Test-Ping, d.h. hier leben wir noch. Also schmiert das Programm ab, wenn es am Ende aufräumen will (wie ich mal annehme, wenn es die object_factory_map fac_map aus der Funktion static object_factory_map& factory_map() zerstören will).

    Habe ich hier irgendwo etwas offensichtlich falsch gemacht?

    Ich habe versucht die Funktion static void __attribute__ ((destructor)) destroy_factories() mal auszukommentieren - es könnte ja sein, dass die auf etwas arbeiten will, dass es zu diesem Zeitpunkt gar nicht mehr gibt - aber das hilft nichts.
    Weg ist der Fehler, wenn ich die Inhalte der Funktionen static void addClass und static void __attribute__ ((destructor)) destroy_factories() auskommentiere. Dann wird ja factory_map() nie aufgerufen und die somit nie die statische object_factory_map fac_map erzeugt (weswegen ich ja annehme, das es beim Zerstören selbiger zum Problem kommt).

    Für Hilfe und Tipps bin ich dankbar. Viele Grüße,
    Maik



  • Brauch "class instantiator" nicht auch einen dtor??

    sonst hätte ich keine idee,..

    mfg



  • kA, obs daran liegt, so ganz seh ich bei deinem Code nicht durch:

    nimm anstatt map<const char*, ...> map<std::string, ...>.

    const char* kann man nicht einfach vergleichen und so, das geht niemals richtig mit const char* in einer std::map als key.

    was soll zB das hier:

    template<> bool cl_reg_context<Child>::placeholder=(instantiator::addClass("Child", new object_factory<Child>), true);
    

    Rufst du da einen Komma-operator auf?

    weiterhin: verwende lieber std::make_pair oder noch besser:

    fac_map()["DieKlasse"]=Ptr_Auf_Die_Fabrik;
    

    Dann wird das ganze schon mal leichter zu durchschauen

    Edit: ach und nochwas:
    Wie du siehst, wird deine Factory_map auch zweimal angelegt, d.h. die .so greift auf die in der .so zu, die executable greift auf eine ganz andere map zu.
    Hab jetz aber auch nich so die Ahnung was man da machen könnte. Und wie du auch siehst, wird nur eine Factorymap davon zerstört, damit kanns auch zusammenhängen



  • Habe eure vorgeschlagenen Änderungen eingebracht, aber das Ergebnis ist noch das gleiche. (neuer Code unten dran)

    Die Zeile

    template<> bool cl_reg_context<Child>::placeholder=(instantiator::addClass("Child", new object_factory<Child>), true);
    

    habe ich mir an anderer Stelle geklaut. Hier geht es nur darum, dass ich die Funktion addClass aufrufen kann, obwohl ich an dieser Stelle gar nicht in einer Funktion bin.

    Das die Factory-Map zweimal angelegt wird ist mir bewusst und auch durchaus beabsichtigt für den Zweck das man ja später eine Bibliothekt A in eine exe einbinden will und aber die Bibliothek A wiederum Bibliothek B benutzt usw. und dann hat jede Bibo ihre eigene Map.

    Also hier der neue Code der child.hpp

    #ifndef CHILD_HPP_
    #define CHILD_HPP_
    
    #include <iostream>
    #include <map>
    #include <string>
    
    struct object_factories{};
    
    template <typename classtype> struct object_factory : public object_factories {
    
    	static classtype* new_instance() { return new classtype; }
    	static void destroy_instance(classtype *&ptr) { delete ptr; ptr = NULL; }
    
    };
    
    class instantiator {
    
    	public:
    
    		instantiator() {}
    		~instantiator() {}
    
    		typedef std::map<std::string, object_factories*> object_factory_map;
    
    		static void addClass(const std::string className, object_factories* object_factory_ptr) { 
    			std::cout << "Registriere Klasse '" << className << "' (Factory-Map: " << &factory_map() << ")" << std::endl;
    			factory_map()[className] = object_factory_ptr;
    		}
    
    		static void __attribute__ ((destructor)) destroy_factories() {
    			for(object_factory_map::const_iterator i = factory_map().begin(); i != factory_map().end(); ++i) {
    				std::cout << "Zerstöre Faktorie für Klasse '" << i->first << "' (Factory-Map: " << &factory_map() << ")" << std::endl;
    				object_factories *ptr = i->second; delete ptr;
    			}
    			factory_map().clear();
    		}
    
    	private:
    
    		inline static object_factory_map& factory_map() {
    			static object_factory_map fac_map;
    			return fac_map;
    		}
    
    };
    
    class Child {
    
    		Child();
    		~Child();
    
    };
    
    namespace {
    
    	template <typename Context> struct cl_reg_context { static bool placeholder; };
    	template <typename Context> bool cl_reg_context<Context>::placeholder = false;
    
    	template<> bool cl_reg_context<Child>::placeholder=(instantiator::addClass("Child", new object_factory<Child>), true);
    
    }
    
    #endif
    


  • Ich habe den Code jetzt so geändert, das die Object-Factory-Map auf dem Heap liegt. Jetzt läufts...


Anmelden zum Antworten