C++ Exceptions verlassen nicht die DLL?
-
hustbaer schrieb:
Du machst dich hier wichtig, indem du den OP und mich über Dinge belehrst die zumindest mir gut bekannt sind, aber vor allem: Dinge die bei der Fragestellung überhaupt nicht relevant sind.
Wenn in einem Diskussions-Forum plötzlich Redebeiträge - wohlgemerkt Beiträge die sehr wohl für das diskutierte Problem relevant sind - als unerwünschte "Belehrungen" abgewatscht werden, dann verfehlt das ganze hier doch seinen Sinn! Was Du oder der OP schon wissen, das ist mir natürlich nicht bekannt. Ich kann nur Dinge erläutern, die meiner Meinung nach für die Analyse und Lösung des Problem wichtig sind, in der Hoffnung, dass es dem Thema weiter hilft!
Falls ein inhaltlich korrekter und in guter Absicht verfasster Post nicht zur sofortigen Lösung des Problems führen sollte, dann ist eine angemessene Antwort: "Danke, dass Du Dir die Zeit genommen hast, diese richtigen und wichtigen Punkte zu erläutern. Leider war mir das meiste davon schon bekannt und ich kann ausschließen, dass mein Problem auf einen dieser Punkte zurückzuführen ist." Damit ist die Sache erledigt und es kann weiter gehen. Eine angemessene Antwort ist sicher nicht "Deine sämtlichen Beiträge hier sind total sinnlos". In wie fern hilft das weiter? Wenn ich etwas "sinnlos" finde, dann derartiges Rumgestänker, wie es ständig aus Deiner Richtung kommt. Sprichst Du im "wahren Leben" etwa auch so mit Deinen Kollegen?
hustbaer schrieb:
Das ist keine Entschuldigung dafür anderen ihre Zeit zu stehlen.
hustbaer schrieb:
Jedem kann mal ein Fehler passieren, man kann Dinge überlesen/übersehen, alles kein Problem. Daher hab' ich auch erst noch ganz sachlich/freundlich geantwortet.
Nur wenn das selbe unpassende Zeug dann wieder und wieder kommt, dann reichts halt irgendwann.Ich stehe weiterhin dazu, dass alles, was ich geschrieben habe, korrekt war. Wenn davon irgend etwas technisch falsch (oder unvollständig) gewesen sein sollte, lasse ich mich gerne korrigieren. Aber ob nun die Punkte, die ich erklärt habe, für das Problem wichtig bzw. relevant sind, darüber mag man subjektiv unterschiedlicher Meinung sein. Ich bin der Meinung, dass ja. Du ganz offensichtlich nicht. So oder so, ist es kein angemessenes Verhalten, meine Beiträge als "sinnlos" abzutun. Selbst wenn Du der Meinung bist, mein Beträge hätten das Thema nicht weiter gebracht (eine Meinung die ich keineswegs teilen kann), dann solltest Du anerkennen, dass hier jemand in guter Absicht versucht zu helfen. Indem Du immer gleich drauf haust, wenn jemand mal - deiner Meinung nach - nicht die "perfekte" Antwort liefert, sorgst Du höchstens dafür, dass dass hier bald keiner mehr Lust verspürt, sich an der Diskussion zu beteiligen. Bei mir hast Du das übrigens geschafft.
DeathCubeUK schrieb:
hustbaer schrieb:
da du im Gegensatz zu mir keine Erfahrung mit dem Thema zu haben scheinst
Mit dieser Behauptung liegst Du falsch.
Naja, macht halt nicht den Eindruck.
DeathCubeUK schrieb:
(...)Einige mögliche Ursachen, die der OP nun überprüfen kann/sollte, habe ich genannt. Das es evtl. doch ein anderes Problem sein könnte, dass noch nicht genannt wurde, habe ich nie ausgeschlossen...
1. Kann der OP ausschließen, dass an irgend einer Stelle evtl. doch "fremd" DLL's im Spiel sind, die (wie ich erläutert habe) sehr wohl Probleme verursachen können, auch dann wenn sie selbst weder Quelle noch Ziel der Exception sind? Ich behaupte an dieser Stelle nicht, dass das das Problem ist, sondern weise lediglich darauf hin, dass man es im Hinterkopf behalten und ggf. überprüfen sollte.
2. Ich habe darauf hin gewiesen, dass es generell besser ist, C++ Exceptions abzufangen, bevor sie die DLL verlassen und stattdessen geeignete Fehlercodes zurück zugeben. Ich spreche dabei aus langjähriger Erfahrung in der Entwicklung diverser kommerzieller Projekte, auf verschiedenen Plattform (Windows, Linux, MacOS) und verschiedenen Compilern (MSVC, GCC/MingW, etc). Du kannst hier natürlich gerne anderer Meinung sein, solltest meine Meining - die ich für durchaus begründet halte - aber trotzdem respektieren!
(Dies wird übrigens auf absehbare Zeit mein letzter Beitrag hier sein. Ich bin es einfach Leid, mich für ein oder zwei Beiträge anschließend endlos rechtfertigen zu müssen)
-
DeathCubeUK schrieb:
Falls ein inhaltlich korrekter und in guter Absicht verfasster Post nicht zur sofortigen Lösung des Problems führen sollte, dann ist eine angemessene Antwort: "Danke, dass Du Dir die Zeit genommen hast, diese richtigen und wichtigen Punkte zu erläutern. Leider war mir das meiste davon schon bekannt und ich kann ausschließen, dass mein Problem auf einen dieser Punkte zurückzuführen ist." Damit ist die Sache erledigt und es kann weiter gehen.
Lies vielleicht nochmal meine erste Antwort an dich in diesem Beitrag:
https://www.c-plusplus.net/forum/p2441806#2441806
Da war bitteschön nichts unfreundliches dran. Ich habe bestätigt dass einige deiner Aussagen korrekt sind bzw. (wörtlich) "zum Teil richtig" sind (inklusive sachlicher Erklärung warum ich es nur für "zum Teil richtig" halte).
Weiters die sachliche Klarstellung dass dein Beitrag auf das Problem des OP nicht anwendbar ist.Nach deiner Aussage könnte es jetzt also "weiter gehen". Tut es aber nicht, denn dann kommt...
https://www.c-plusplus.net/forum/p2441814#2441814
Eine weitere Belehrung über immer noch (auf die Fragestellung bezogen) total irrelevante Dinge.Und dann fängt es halt an lästig zu werden, weil sich ein gewisses Bild abzeichnet.
DeathCubeUK schrieb:
Dies wird übrigens auf absehbare Zeit mein letzter Beitrag hier sein.
OK. Wenn du meinst.
DeathCubeUK schrieb:
Ich bin es einfach Leid, mich für ein oder zwei Beiträge anschließend endlos rechtfertigen zu müssen
Die alternative Lösung dafür wäre: schreib Beiträge die besser zum Thema passen.
-
DeathCubeUK schrieb:
Ich bin es einfach Leid, mich für ein oder zwei Beiträge anschließend endlos rechtfertigen zu müssen
Musst du nicht. Tue es nicht.
-
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.)
-
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?
-
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...
-
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-caughtAber 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.
-
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 inMyDummySetUnhandledExceptionFilter
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-NatiIch 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?