Jeden Crash abfangen



  • Hi!

    Ich möchte jeden Crash eines Programms abfangen, um noch Logs schreiben zu können. Habe mir schon das http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus angesehen und alle diese Handler installiert. Danach ein bisschen Mist gebaut, doch es erscheint das bekannte Fenster "...exe funktioniert nicht mehr" (nicht immer, kommt drauf an, wie ich den Crash verursache).

    Was denn noch alles? Wie kann ich jeden, wirklich jeden Crash abfangen? /EHa und /EHs auch schon probiert, auch SetThreadStackGuarantee(1M);

    Die Codes, die nicht abgefangen werden: 0xc0000005 (access violation) und 0xc0000409 (unknown software exception)
    (Mehr hab ich noch nicht probiert)

    (Bei 0xc0000409 zB. bekomme ich in Visual Studio ein "buffer overrun ..." Fenster, wenn ich die .exe jedoch ohne VS starte, nur ein "... funktioniert nicht mehr")

    So erzeuge ich zB. 0xc0000409:

    unsigned char buf[] = { 1, 2, 3, 4 }; // zu klein
    
    unsigned int param[10]; // auch zu klein
    unsigned int ind = 0;
    
    for(unsigned int i = 0; i < 100; ++i)
    {
    	param[i] = *(unsigned int*)&buf[ind];
    	ind += 4;
    }
    
    for(int i = 0; i < 10; ++i)
    	cout << param[i] << endl;
    

    Wiegesagt, ich will gar nicht genau wissen, was passiert, sondern einfach nur noch Logs schreiben, bevor "... funktioniert nicht mehr" erscheint.

    😕



  • Hmm komisch, wenn ich einen VectoredHandler mit AddVectoredExceptionHandler hinzufüge, wird dieser aufgerufen!
    Warum nicht mit SetUnhandledExceptionFilter? Den Crash verursache ich direkt danach...


  • Mod



  • Ah interessant, aus SetUnhandledExceptionFilter wird also ein dummy gemacht. Ok, jedoch möchte ich solche Aufrufe schon zulassen, da ich ein bereits vorhandenes Programm modifiziere, welches diese Funktion nutzt.
    Der Link zu den buffer overruns "can never be catched in your filter" funktioniert nicht mehr. Können die dann auch nicht gefangen werden? Muss man also /GS- nutzen?
    Wenn man allerdings einen VectoredHandler benutzt, sollte der dummy doch gar nicht nötig sein? Denn ein VecHandler wird ja sowieso immer aufgerufen?!



  • /GS ruft immer direkt WER auf!
    Das hat auch nicht unbedingt was mit Deiner Anwendung zu tun, sondern die Windows-DLLs sind auch so übersetzt.
    Das hat auch nichts mit Vectored-Exception-Handlern zu tun...

    Wenn der Check durch /GS einen Bufferüberlauf feststellt, so wird zwangsweise *sofort* WER aufgerufen. Und zwar durch aufruf von "SetUnhandledExceptionFilter(NULL)" und dann durch aufruf von UnhandledExceptionFilter (was dann der Windows-Default ist, was dann WER aufruft)...

    Fazit: Exceptions von EXE/DLLs, welche mit /GS übersetzt sind (heute fast alle) kann man nicht abfangen. Es sei denn man verhindert den Aufruf von "SetUnhandledExceptionFilter(NULL)".



  • Aha okay, verstehe, danke!



  • Hmm, bei 0xc0000005 access violation kommt doch wieder WER! Nur, wenn ich einen VectoredHandler setze, wird dieser auch aufgerufen. Alle anderen Handler werden nicht aufgerufen. Warum ist das so?



  • Ist eine Access-Violation eine *Security-Exception*??????
    Ich hab hier nur von /GS geredet; und das hat mit *Security* zu tun!

    Prinzipiell gilt hier die Regel: Wenn das Programm manipuliert wurde (beabsichtlicht oder unbeabsichtlich, z.B. durch Speicherüberschreiber), so ist dem Prozess nicht mehr zu trauen! Somit darf auch auf keinen Fall ein installierter Handler im selben Prozess aufgerufen werden.



  • Wenn bei Dir eine AV nicht abgefangen wird, so hat einfach eine anderer Software seinen eigenen Handler installiert und fängt diese ab...

    Beachte auch, dass man sowas nicht (invasive) debuggen kann, da hier nie ein Unhandled-Exception-Handler aufgerufen wird. Das kann man nur "non-invasiv" debuggen....



  • Ich kapiers nicht...

    #include <Windows.h>
    #include <iostream>
    using namespace std;
    
    LONG WINAPI SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
    {
    	MessageBox(0, "SehHandler", 0, 0);
    	return EXCEPTION_CONTINUE_SEARCH;
    }
    
    int main()
    {
    	SetUnhandledExceptionFilter(SehHandler);
    
    	// Crash 1
    	*(unsigned int*)(0) = 0;
    
    	// Crash 2
    	unsigned char buf[] = { 1, 2, 3, 4 };
    
    	unsigned int param[10];
    	unsigned int ind = 0;
    
    	for(unsigned int i = 0; i < 100000; ++i)
    	{
    		param[i] = *(unsigned int*)&buf[ind];
    		ind += 4;
    	}
    
    	for(int i = 0; i < 10000; ++i)
    		cout << param[i] << endl;
    }
    

    Nur Crash 1 (Crash 2 auskommentiert): SehHandler
    Nur Crash 2 (Crash 1 auskommentiert): WER (0xc0000005)
    Beide (nichts auskommentiert): WER (0xc0000005)

    Füge ich noch einen VectoredHandler hinzu, wird dieser bei allen drei Varianten aufgerufen.

    😕



  • Mit was für einem Exception-Model wird Dein Projekt übersetzt?
    Beachte, dass per Default /EHsc aktiviert ist; Du solltest aber /EHa verwenden...
    Und überschreibe mal nicht so viel... sonst kann es ja sein, dass Dein ganzes Programm ungültig wird...



  • /EHa war bereits gesetzt.

    Jochen Kalmbach schrieb:

    Und überschreibe mal nicht so viel... sonst kann es ja sein, dass Dein ganzes Programm ungültig wird...

    Könnte sich aber um ein realistisches Szenario in einem fremden Programm handeln. Ich möchte halt, wie schon gesagt, auf jeden Crash reagieren können.



  • Wie Du gerade schon selber gesagt hast, ist dies nicht möglich.... wenn ich davon ausgehe, dass sehr viel Speicher überschrieben wird, dann kann auch mein Handler überschrieben sein... somit ist Dein Ansatz falsch.
    Es gibt *keine* Möglichkeit _alle_ Exceptions abzufangen... nur eine hohe Wahrscheinlichkeit...

    Und was erwartest Du, wenn Du "EXCEPTION_CONTINUE_SEARCH" zurück gibst???? Dann kommt WER...



  • Bei mir funktioniert Dein Beispiel wunderbar... habe nur ein "printf" anstelle "MessageBox" gemacht.... je nachdem ob die DLL schon geladen ist, kann es kritisch sein ein DllMain in einem Exception-Handler zu verwenden....

    Mit der MessageBoxA geht es bei mir aber auch...



  • Achso, das ist ja sch... 😞

    Noch ein Problem: Wenn ich den VectoredHandler im fremden Programm setze, wird er auch noch aufgerufen, nachdem ich schon längst wieder RemoveVectoredExceptionHandler erfolgreich aufgerufen habe.
    Wie kann das sein?



  • Ich verstehe nicht genau was Du erreichen willst...



  • Ein fremdes Programm wird um eine DLL erweitert. Diese soll möglichst alle Crashes abfangen.
    Das Problem ist, dass sowohl beim normalen Start als auch beim normalen Beenden des Programms ein paar Exceptions fliegen...
    Ich warte also ein wenig, bevor ich AddVectoredExceptionHandler aufrufe.
    Beim Schließen des Programms rufe ich dann RemoveVectoredExceptionHandler auf, damit mein VecHandler nicht mehr aufgerufen wird, wird er aber trotzdem, einige Sekunden nach dem Remove-Aufruf.



  • Jochen Kalmbach schrieb:

    Bei mir funktioniert Dein Beispiel wunderbar...

    Warum bei mir nicht 😞 Auch nicht mit printf, es erscheint garnix, gleich WER. Habe nix spezielles installiert, keinen AV oder sonstigen Kram...


  • Mod

    Und warum bitte machst Du das nicht mit WER?



  • Weil ich dann keine (sehr wichtigen crashrelevanten) Logs mehr schreiben kann.

    Zu dem RemoveVectoredExceptionHandler funktioniert nicht: Sorry, mein Fehler. AddVectoredExceptionHandler wurde danach nochmal durch eine HookInit-Funktion aufgerufen (Init bei Beendigung des Programms, naja...).


Anmelden zum Antworten