C++ Exceptions verlassen nicht die DLL?



  • hustbaer schrieb:

    Versuch mal ein neues, frisches EXE Projekt anzulegen und ein neues, frisches DLL Projekt, und dann mal den minimal nötigen Code schreiben um das zu testen. Also eine Funktion exportieren die z.B. nen std::runtime_error wirft, und die im Hauptprogramm in einem try-catch(std::exception const&) aufrufen.

    Ich habe jetzt mal eine komplett neue Solution mit minimalen Projekt-Inhalten erstellt. Tatsächlich funktioniert hier, dass die Exception die DLL verlässt.

    Das habe ich in meinem ursprünglichen Projekt anders:

    Ich benutze dort die ATL (sind nur Termplates), d2d1.lib (Direct2D), dwrite (DirectWrite) und Windowscodecs.lib.

    Sonst fällt mir nicht weiter ein, was ich ggü. dem Dummy-Projekt anders habe.
    🙄

    Kann es an den D2D Libs liegen?



  • Weil du die ATL erwähnst: ist hier evtl. COM im Spiel?
    Falls ja könnte ich mir evtl. vorstellen dass COM da irgendwie dazwischenpfuscht - vielleicht ein automatisch erstellter Proxy oder sowas.

    Nur die Verwendung der ATL ist auf jeden Fall kein Problem. Ich habe hier auch ein Projekt wo in der .EXE die ATL verwendet wird, wo die .EXE etliche (nicht-COM) DLLs nachlädt, die Fehler mittels Exceptions kommunizieren. Funktioniert alles wie es sollte.

    Was D2D angeht: damit hab ich keine Erfahrung. Würde mich aber wundern wenn das irgendwie relevant wäre.

    Nochwas: du schreibst die Exception "geht verloren". Was passiert denn statt der erwarteten Ausfürhung des catch-Blocks?
    Läuft die Funktion nach der "throw" Anweisung weiter? Oder geht's an der DLL-Boundary weiter als ob die Funktion normal beendet worden wäre? Oder ...?

    Ansonsten kann ich dir nur noch empfehlen: bau Stück für Stück die Dinge die in dem Projekt drinnen sind wo es nicht funktioniert aus, und teste nach jedem Schritt ob es immer noch Probleme macht. (Oder auch umgekehrt: bau Stück für Stück die anderen Dinge ein, ausgehend von dem Projekt wo es jetzt funktioniert.)


  • Mod

    Liegen Aufrufe von Fensterprozeduren auf dem Stack?
    COM Aufrufe?



  • Martin Richter schrieb:

    Liegen Aufrufe von Fensterprozeduren auf dem Stack?
    COM Aufrufe?

    Ich verwende die ATL um Fenster mittels CWindow zu erzeugen und die Messages zu behandeln. Ob ich die CWindow-Objekte auf dem Stack erzeugt habe, muss ich heute Abend im Code nachschauen.

    Bei den COM-Aufrufen, dürften ja die ganzen DirectXYZ-APIs dazu gehören?


  • Mod

    Wenn bestimmte Exceptions innerhalb von SendMessage und einer Fenster Prozedur auftreten, dann werden die auch "gefressen". Das kann ich auch immer wieder beobachten.



  • hustbaer schrieb:

    Nochwas: du schreibst die Exception "geht verloren". Was passiert denn statt der erwarteten Ausfürhung des catch-Blocks?
    Läuft die Funktion nach der "throw" Anweisung weiter? Oder geht's an der DLL-Boundary weiter als ob die Funktion normal beendet worden wäre? Oder ...?

    Ich werfe in der DLL eine Exception, z.B. throw int(1); . Im Debugger kann ich dann auch das Stack-Unwinding mitverfolgen (z.B. weil das Throw etwas tiefer in der DLL passiert). Es kommt auch ein First-Chance-Exception auf dem Trace-Output. Das Unwindig hört aber an der ersten DLL-Funktion auf. Es passiert nichts weiter bzw. es geht dann normal mit dem Programmablauf weiter. Und in der EXE ist als ob nichts gewesen ist, obwohl ich in der EXE die DLL-Funktion (die den throw wirft) aufgerufen habe.

    Normalerweise müsste ein Unhandled Exception kommen. Wenn ich in der Exe ein try Catch einbaue, gehts auch nie den Catch Block.



  • Martin Richter schrieb:

    Wenn bestimmte Exceptions innerhalb von SendMessage und einer Fenster Prozedur auftreten, dann werden die auch "gefressen". Das kann ich auch immer wieder beobachten.

    Mein erste Versuch eine Exception zu werfen, war bei einem WM_PAINT. Meine erste Vermutung war, das die ATL Messages vielleicht einen catch-Block haben o.ä. Konnte in den ATL Sourcen nichts finden.

    Deshalb hatte ich als Test auch probiert, eine Exception zu werfen, die nichts mit ATL zu tun hat:

    // Dummy Code in der EXE
    int WinMain()
    {
    MyAtlWindow w; // DLL
    w.show();
    
    MyPlainClass c; // DLL
    c.foo(); // hier drin wird eine exception geworfen!
             // First-Chance Exception, aber kein Unhandled Exception
    
    while() { aufwändiger windows message loop kram }; 
    }
    

    Da es auch so nichts bewirkt hat, hatte ich ATL bzw. CWindow-Messages ausgeschlossen.

    Ich könnte heute Abend probieren in meiner Solution die CWindow Erzeugung weg zu lassen. Und dann al schauen ob es funktioniert. Ich ahne es aber schon, das wahrscheinlich das ganze Window-Handling in der DLL daran schuld ist... 🙄


  • Mod

    Das Exceptions in einem WM_PAINT Block "gefressen" werden ist ein bekanntes Problem, das zum Teil auch noch durch Bugs verschärft wird. (Siehe auch http://support.microsoft.com/kb/976038).

    Siehe auch Diskussion hier:
    http://stackoverflow.com/questions/1487950/access-violation-in-wm-paint-not-caught

    Aber dennoch ist mir unklar, was bei Dir passiert mit der "plain class". Irgendwie leuchtet mir das nicht ein und mir scheint ein weiterer Exception Handler zu existieren.

    Was sagt SetUnhandledExceptionFilter wenn Du es explizit auf NULL setzt? Ist einer gesetzt gewesen? Was passiert nun, wenn er nicht NULL war?



  • @Martin Richter
    Weisst du ob diese "exceptions in callbacks werden gefressen" Geschichte mit SP1 behoben wurde (gibt ja nen Hotfix)?
    EDIT: OK, never mind, hab's selbst grad gefunden: ja, ist drinnen. => Sollte heute also kein Problem mehr sein.


  • Mod

    Also ich habe gerade aktuell ein "ähnliches" Problem.

    Sieht aber "ganz anders" aus. Ich habe einen COM Server.
    Der wird angesprochen und mache "viele" Sachen (Fenster erzeugen, Daten umsetzen etc.).
    Jetzt habe ich den Fall, das ein bestimmter COM Zeiger im Server 0 ist. Dieser wird auch verwendet 😞 es kommt zu einer First Chance Exception im Debugger und das war es.

    Mein Exception Handler schreibt einen Minidump und crashed, aber der wird nicht angesprungen...

    Und ehrlich gesagt verstehe ich es auch nicht. Nachvollziehbar auf einem Win 8.1 und Win 7 Rechner. Beides 64bit. Anwednung ist 32bit.

    Exception tritt in der EXE auf und es sind gefühlte 1000 DLLs geladen.



  • @Martin & Artchi
    Könnt ihr nen 64 Bit Build machen und/oder die 32 Bit EXE mal auf nem 32 bittigen Windows (selbe Version/SP-level wie das wo ihr sonst testet, nur halt 32 Bit) laufen lassen?

    Dann wüsste man zumindest mal ob es was mit dieser "64 Bit Windows frisst Exceptions" Geschichte zu tun hat.

    Was mir sonst noch einfällt ist die .NET Runtime. Aber wenn die geladen wäre hättet ihr das vermutlich erwähnt, und IIRC pfuscht die auch nur ins SEH Handling rein während irgendwo managed Code auf dem Callstack ist.

    ps:
    Oder vielleicht mal folgenden Code probieren (achtung, irgendwer hat die "==" in dem Listing gefressen):
    http://blog.kalmbachnet.de/?postid=75
    EDIT: Jochen hat die fehlenden "==" ersetzt und mir nen Link auf die neue, verbesserte Version geschickt:
    http://blog.kalmbach-software.de/2013/05/23/improvedpreventsetunhandledexceptionfilter/
    /EDIT
    und dann nen Breakpoint in MyDummySetUnhandledExceptionFilter reinsetzen.
    Und sich den Callstack von jedem angucken der das aufruft.

    ps2:
    Eigentlich müsste es reichen nen Breakpoint in SetUnhandledExceptionFilter zu setzen. Wobei ich die Syntax dafür immer wieder vergessen...



  • Ich habe jetzt mal den Build auf x64 umgestellt. Und tatsächlich kommt jetzt die Exception bis zur Exe durch und ich erhalte auch ein Unhandled Exception. Das nachträgliche abfangen mit catch funktioniert auch!

    Als weiteren Test habe ich mein Projekt wieder auf Win32 umgestellt, die ATL Windows _nicht_ instantiiert und wieder in einer Plain DLL Class eine Exception geworfen: Exception kommt durch!

    Wenn ich das richtig verstehe, machen die Fenster in einer Win32-DLL auf einem X64-Windows Probleme. Ohne Fenster kommen die Exceptions bei dieser Kombi durch.

    Den SetUnhandledExceptionFilter auf Null setzen, werde ich nachher ausprobieren.



  • Ich habe SetUnhandledExceptionFilter(NULL) gesetzt und ein ATL Fenster erstellt, und jetzt wird unter Win32 Build auch die Exception bis zur EXE durch geworfen! 👍

    Kann man raus finden, welcher Handler dort drin steckt, bevor ich ihn auf Null setze?



  • Hm.
    Das ist irgendwie ... krass. Wir wissen also jetzt dass es etwas mit 32 Bit EXEn auf nem 64 bittigen Windows zu tun hat. Und irgendwie irgendwas mit Fenstern.

    Wobei ich nicht glaube dass es hier ein allgemeines Problem mit Fenstern gibt - sonst würden ja massig Windows Anwendungen nicht mehr funktionieren (bzw. deren Error-Handling). Die MFC z.B. verwendet ja auch Exceptions, und MFC Extension DLLs sind auch nicht gerade SO selten.

    Und ich frage mich jetzt ob das ganze überhaupt irgendwas mit DLLs zu tun hat. Kannst du das nochmal probieren? Also z.B. die Definition von "MyPlainClass" in die EXE verschieben - ohne weitere Änderungen? Ich kann mir nämlich grad nicht vorstellen wieso das was mit DLL vs nicht-DLL zu tun haben sollte. Wobei es natürlich möglich ist, der Exception Filter könnte ja gucken in welchem Modul die Exception aufgetreten ist, und unterschiedliche reagieren je nachdem ob es das Modul des EXE Files oder ein anderes Modul ist. Ich frage mich aber wieso er das tun sollte.

    Noch ein Versuch wäre: erzeug mal ein Fenster direkt mit WinAPI, also ohne ATL. Wäre interessant was dann passiert.



  • Artchi schrieb:

    Kann man raus finden, welcher Handler dort drin steckt, bevor ich ihn auf Null setze?

    Du kannst nen Breakpoint in SetUnhandledExceptionFilter setzen.

    Müsste mit Debug->New Breakpoint->Break at Function...
    Function: {,,kernel32.dll}SetUnhandledExceptionFilter
    gehen.

    Siehe
    http://www.highprogrammer.com/alan/windev/visualstudio.html
    bzw.
    http://www.codeproject.com/Articles/518159/Even-More-Visual-Studio-Debugging-Tips-for-Nati

    Ich würde das, also SetUnhandledExceptionFilter(0) , auch nicht als Lösung ansehen. Sondern versuchen rauszufinden ob es nicht einen weniger krassen Workaround gibt.



  • Sehr mysteriös, habe alles wieder zurück genommen (auf Win32 Build zurück und SetUnhandledExceptionFilter entfernt). Die Exception schlägt weiterhin durch. OK, Clean Solution und Rebuild. Schlägt immer noch durch. 😮

    PC neu booten. Schlägt immer noch durch! 😡

    Gesamte Solution inkl. Configfiles per Sourcecode Management UNDO. Jetzt schlägt die Exception nicht mehr durch.

    OK, jetzt setze ich SetUnhandledExceptionFilter(NULL)... und die Exception schlägt wieder nicht durch. 😡 Am SetUnhandledExceptionFilter kann es also nicht liegen. Wahrscheinlich an der x64 Config alleine, obwohl ich vor dem Undo auf Win32 gestellt hatte.

    Für heute Nacht ist erst mal Schluss... werde Morgen nochmal ein paar Konstellationen ausprobieren.



  • Artchi schrieb:

    Gesamte Solution inkl. Configfiles per Sourcecode Management UNDO. Jetzt schlägt die Exception nicht mehr durch.

    Waaah, hast du vorher nen Backup oder wenigstens ein Diff gemacht?


  • Mod

    Reply auf eine frühere Frage:

    SetUnhandledExceptionFilter gibt Dir den alten Handler zurück...



  • hustbaer schrieb:

    Artchi schrieb:

    Gesamte Solution inkl. Configfiles per Sourcecode Management UNDO. Jetzt schlägt die Exception nicht mehr durch.

    Waaah, hast du vorher nen Backup oder wenigstens ein Diff gemacht?

    Bevor ich das Undo gemacht hatte, habe ich mit einem Diff geschaut was sich alles geändert hatte. Es waren nur die hier in meinen Posts genannte SetUnhandledExceptionFilter(NULL) und die x64 Config.
    Genau das hat mich verwundert...

    Kein Drama. Werde mich heute Abend nochmal dazu melden.



  • hustbaer schrieb:

    Noch ein Versuch wäre: erzeug mal ein Fenster direkt mit WinAPI, also ohne ATL. Wäre interessant was dann passiert.

    Habe ohne ATL ein Fenster in einer DLL erzeugt (Win32 Build). Exception kommt dann auch bis zur EXE durch.


Anmelden zum Antworten