Exception Handling - Microsoft spezifisch



  • hallo,

    erstmal Beispiel Quellcode:

    int	main(int argc, char* argv[], char* envp[]);
    void	Recursion4Ever();
    void	SE_Translator(UINT nErrCode, _EXCEPTION_POINTERS* e);
    
    class CStackOverFlowException 
    {};
    class CAccessViolationException
    {};
    
    void	SE_Translator(UINT nErrCode, _EXCEPTION_POINTERS* /*e*/)
    {
    	switch (nErrCode) {
    		case	EXCEPTION_STACK_OVERFLOW:
    			throw	new CStackOverFlowException;
    		case	EXCEPTION_ACCESS_VIOLATION:
    			throw	new CAccessViolationException;
    		default:
    			exit(nErrCode);
    	}
    }
    
    void	Recursion4Ever()
    {
    	free(malloc(0));
    	asm	sub	 esp, 0x10		//	bisschen beschleunigen den Vorgang
    	asm	call	Recursion4Ever
    }
    
    int main(int argc, char* argv[], char* envp[])
    {
    	_set_se_translator(SE_Translator);
    
    	try {
    		Recursion4Ever();
    	} catch (CStackOverFlowException* e) {
    		cout << "Stack Overflow!\n";
    		delete	e;
    	} catch (CAccessViolationException* e) {
    		cout << "Access Violation!\n";
    		delete	e;
    	}
    
    	system("pause");
    
    	return 0;
    }
    

    folgendes Problem besteht nun:

    falls die Stack Overflow Exception irgendwo bei durch malloc oder free ausgelöst wird, wird die SE_Translator Funktion nicht aufgerufen, so das ich auch keine Fehler catchen kann 😞
    Das liegt evtl. daran (ich bin mir nicht ganz sicher), dass DLL's ihre eigene Translator-Funktion haben, ich müsste also für die DLL bzw. alle DLL's irgendwie die Translator Function setzten.
    (jedenfalls hat jeder Thread seine eigene.)

    Wäre echt nett, falls mir da jemand helfen kann 🙂

    MfG
    DDR-RAM

    P.S.:
    Nicht von den beiden Assembleranweisungen beunruhigen lassen, die ham nur den vorteil, das MS VC++ da nicht mit rumdoktort.



  • kann auch nur raten. 😉
    1. sollten exceptions nicht bei value geworfen werden? zumindest ist dieses bei c++ exceptions so.
    2. compiler flag beachtet

    msdn schrieb:

    Use /EHa instead of /EHsc when using _set_se_translator.

    3. hat nichts mit deinem fehler zu tun. _set_se_translator würde ich der sauberkeit halber auch in den try block schreiben.



  • miller_m schrieb:

    kann auch nur raten. 😉
    1. sollten exceptions nicht bei value geworfen werden? zumindest ist dieses bei c++ exceptions so.
    2. compiler flag beachtet

    msdn schrieb:

    Use /EHa instead of /EHsc when using _set_se_translator.

    3. hat nichts mit deinem fehler zu tun. _set_se_translator würde ich der sauberkeit halber auch in den try block schreiben.

    hi, erstmal generell danke 😃

    aber,
    zu 1. das man pointer wirft ist vollkommen legitim und standardkonform (soweit ich weiß)
    zu 2. hab ich, sonst kann kommt sogar ein Compilerfehler
    zu 3. ist mir nicht bekannt, das _set_se_translator was wirft, aber schaden kanns nicht, werd da maln nen bisschen was testen,

    alles in allem bin ich also noch nicht soo 😃 viel weiter.
    kann allerdings selber eine Idee einbringen 🙂
    ich könnte vor allen malloc aufrufen überprüfen ob noch genügend stack vorhanden ist, naja wäre halt ein wenig umständlich 😞

    hier mal der erweiterte Code (damit funktioniert dann auch alles richtig)

    void	CheckStack(int nStackSize)
    {
    	_alloca(nStackSize);
    }
    
    void	Recursion4Ever()
    {
    	CheckStack(0x1000);	//	eine page
    	free(malloc(0));
    	__asm	sub		esp, 0x10		//	bisschen beschleunigen den Vorgang
    	__asm	call	Recursion4Ever
    }
    

    Aber vielleicht gibt es da auch ne Möglichkeit die so ähnlich ist.
    wäre echt cool, wenn jemand da helfen könnte,
    aber solange muss ich es auf wohl noch auf meine TODO-List setzten

    MfG
    DDR-RAM



  • Normalerweise kann man SEH und C++ Exceptions nicht mischen.

    Ich wuerde zuerst einen SEH-Handler schreiben, also mit "_try .. _catch ( )", wobei in der _catch-Zeile der SEH-Handler aufgerufen wird. Die Funktion, die den SEH-Handler enthaelt, gibt z.B. bloss einen Returncode zurueck. Die aufrufende Funktion wirft dann eine C++ Exception. Damit haettest Du die beiden Exception-Systeme getrennt.

    Bei DLLs ist es ratsam, sowohl einen SEH Handler, als auch einen C++ Handler zu haben, damit ein DLL API niemals eine Exception werfen kann. Ausserdem sollte man die Exception-Semantik auf auesserster DLL-Ebene durch das Kapseln des DLL-Interfaces mittels " extern "C" { ... } " entfernen. Dadurch wird die DLL unabhaengig vom verwendeten Compiler, da auch kein Name-Mangling mehr stattfindet. Auf der aufrufenden Seite kann man dann das C-API der DLL wieder in Klassen kapseln.



  • Die verschieden EH-Typen darf man mischen nur nicht in der selben Funktion.

    Bin jetzt auf den Verursacher des ersten Teils meines Problems gestoßen und da kann man dann auch schnell was lösen, werd hier nochmal posten, falls es wen interessiert 😃

    Danke Power Off, du hast mir einen entscheidenden Denkanstoss gegeben, der wenig mit deinem gesagten zu tun hat 😉

    MfG
    DDR-RAM



  • Ja, mich interessiert's 🙂



  • Der Quelltext (aus meinem ersten Post):

    void    Recursion4Ever()
    {
        free(malloc(0));
        asm    sub     esp, 0x10        //    bisschen beschleunigen den Vorgang
        asm    call    Recursion4Ever
    }
    

    Das Problem:

    malloc gibt bei Fehler NULL zurück, free kehrt bei übergebenen NULL-pointer sofort zurück. Da irgendwann, wenn der stack fast voll ist, malloc NULL zurückgibt und den Heap in einem beschädigten zustand zurücklassen wird,
    folgt beim nächsten Aufruf von malloc eine Access Violation.

    Lösung:

    Man muss ich den Rückgabewert von malloc (in diesem Fall) überprüfen.
    Und ggf. mit GetLastError checken, ob ein Stack Overflow aufgetreten ist
    (GetLastError() == ERROR_STACK_OVERFLOW)
    Eine weitere möglichkeit wäre einen newhandler zu etablieren.

    wie gesagt, bei mir funct alles oder besser gesagt, ich weiß wieder wie ich alles zum funktionieren bringe.
    also wer noch Fragen hat, ich bin jetzt Meister 😃
    (waren aber auch Anfängerfehler :()

    MfG
    DDR-RAM



  • Und dann? Dann ist der Heap kaputt, und man crasht erst recht ziemlich bald.



  • Ringding schrieb:

    Und dann? Dann ist der Heap kaputt, und man crasht erst recht ziemlich bald.

    Wie was?
    Wovon soll der Heap denn jetzt kaputt gehen?
    NewHandler doch nicht? und Rückgabewert überprüfen?

    😕 😕 😕

    MfG
    DDR-RAM



  • malloc NULL zurückgibt und den Heap in einem beschädigten zustand zurücklassen wird

    Du hast doch geschrieben, dass der Heap beschädigt zurückgelassen wird.



  • Ringding schrieb:

    malloc NULL zurückgibt und den Heap in einem beschädigten zustand zurücklassen wird

    Du hast doch geschrieben, dass der Heap beschädigt zurückgelassen wird.

    oh sry, my fault, ich meinte der stack wird in einem beschädigten Zustand zurückgelassen.
    Erklärung folgt sofort:

    Dabei werden auch nicht irgendwelche Datenbeschädigt sondern nur die Guard Page, die normalerweise das Ende des Stacks markiert existiert nicht mehr, damit bekommt man beim nächsten Zugriff auf diese Speicherseite keinen Stack Overflow sondern ne Access Violation.
    Ich hoffe ich hab nicht für zu große Verwirrung gesorgt 🙄

    MfG
    DDR-RAM



  • Jetzt klingt's vernünftig 🙂


Anmelden zum Antworten