Programmabsturz bei unbehandelter Exception - still und leise ohne Meldung

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von siycah.

    Programmabsturz bei unbehandelter Exception - still und leise ohne Meldung

    wie erwähnt hatte ich eigentlcih gedacht, das bei einer unbehandelten Expection Windows IMMER eine Meldung dazu schmeißt. Da habe ich mich wohl getäuscht. Das Projekt wurde sogar mit aktiviertem Debug kompiliert, damit ich die Zeilennummer habe. Trotzdem: einfach so stürzt das Programm ab.
    Nun finde ich die zugehörige Meldung in der Ereinisanzeige:

    Protokollname: Application
    Quelle: .NET Runtime
    Datum: 24.02.2023 13:16:31
    Ereignis-ID: 1026
    Aufgabenkategorie:Keine
    Ebene: Fehler
    Schlüsselwörter:Klassisch
    Benutzer: Nicht zutreffend
    Computer: W10JOB
    Beschreibung:
    Anwendung: XPadsStarter.exe
    Frameworkversion: v4.0.30319
    Beschreibung: Der Prozess wurde aufgrund einer unbehandelten Ausnahme beendet.
    Ausnahmeinformationen: System.Collections.Generic.KeyNotFoundException
    bei System.ThrowHelper.ThrowKeyNotFoundException()
    bei System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].get_Item(Int32)
    bei XPads.fmMain.grdErgebnis_CellFormatting(System.Object, System.Windows.Forms.DataGridViewCellFormattingEventArgs)
    bei System.Windows.Forms.DataGridView.OnCellFormatting(System.Windows.Forms.DataGridViewCellFormattingEventArgs)
    bei System.Windows.Forms.DataGridView.OnCellFormatting(Int32, Int32, System.Object, System.Type, System.Windows.Forms.DataGridViewCellStyle)
    bei System.Windows.Forms.DataGridViewCell.GetFormattedValue(System.Object, Int32, System.Windows.Forms.DataGridViewCellStyle ByRef, System.ComponentModel.TypeConverter, System.ComponentModel.TypeConverter, System.Windows.Forms.DataGridViewDataErrorContexts)
    bei System.Windows.Forms.DataGridViewCell.GetEditedFormattedValue(System.Object, Int32, System.Windows.Forms.DataGridViewCellStyle ByRef, System.Windows.Forms.DataGridViewDataErrorContexts)
    bei System.Windows.Forms.DataGridView.OnCellValidating(System.Windows.Forms.DataGridViewCell ByRef, Int32, Int32,


    da frag ich nun : wieso muss sich die exe so still und leise verabschieden? Wieso dem Entwickler das Leben so schwer machen?
    @Coldfire Du kannst zunächst in den ApplicationEvents die UnhandledException oder so abbonieren und Dich dann rantasten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich hoffe, dass das nicht was bei Dir mit Nebenläufigkeit zu tun hat.
    Wenn eine meiner Apps abschmiert, dann nie klammheimlich. Alle sind nur als Debug-Version unterwegs, damit Fehler definitiv dem User gemeldet werden (auch wenn ich eine eigene Fehlerauffangmethode eingebaut habe, um es komfortabler inkl. Screenshot zu loggen). Bei Release-Konfiguration soll ein Absturz angeblich stillschweigend sein.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Coldfire schrieb:

    auf einem anderen Rechern so geschieht.
    Was ist denn auf diesen Rechnern separat zu installieren, wenn es bei Dir nicht knallt?
    Erstelle eine Log-Datei, in der Du z.B. jeden Prozedur-Aufruf loggst.
    Wenn es dann knallt, weißt Du schon mal etwas mehr, dann kannst Du das Logging verfeinern.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich kann Rod nur zustimmen.

    In deinem aktuellen Fall ist es ja klar, wo der Fehler liegt; du prüfst vorher nicht ob ein Key existiert bevor du einen Value einfügst, aber das kann ja immer mal passieren.

    Du kannst ein Logging-Framework wie Serilog oder NLog verwenden und in jeder Methode einfach pauschal ein ​trace/verbose Log ausgeben:

    VB.NET-Quellcode

    1. public class TestClass
    2. dim m_appLogger as ILogger ' ILogger ist von Serilog
    3. public sub new(appLogger as ILogger) ' ILogger wird am Besten in deiner Main erstellt
    4. appLogger.Verbose("Entered " & nameof(TestClass) & " constructor")
    5. m_appLogger = appLogger
    6. end sub
    7. public sub DoSomething()
    8. m_appLogger.Verbose("Entered " & nameof(DoSomething) & " in " & nameof(TestClass))
    9. m_appLogger.Verbose("Exiting " & nameof(DoSomething) & " in " & nameof(TestClass)) ' optional, aber kann beim Debuggen hilfreich sein
    10. end sub
    11. end class


    Du kannst in deiner Configdatei dann natürlich das LogLevel anpassen und deinen Usern sagen, dass die diese Einstellungen treffen sollen, wenn dieser Fehler eintritt.
    Dann können sie dir einfach die Logdatei schicken.

    Für Serilog kann ich dann rehansaeed.com/logging-with-serilog-exceptions/ dieses Modul zusätzlich empfehlen.
    Dann kannst du in dem ​AppDomain.UnhandledException mittels Serlog noch die Exception ausgeben lassen, mit allen Details.

    Anbei noch ein Beispiel, wie das aussehen kann mit Serilog:
    Spoiler anzeigen

    Quellcode

    1. ​[17:11:02 ERR] Command execution failed! Command: load-plugin ../Plugins/Hermod.EmailImport.dll
    2. System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
    3. Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
    4. Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
    5. Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
    6. at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
    7. at System.Reflection.Assembly.GetTypes()
    8. at Hermod.PluginFramework.PluginRegistry.ContainsPlugins(Assembly assembly, List`1& pluginTypes) in /Users/simon/Projects/Hermod/Hermod/PluginFramework/PluginRegistry.cs:line 119
    9. at Hermod.PluginFramework.PluginRegistry.LoadPlugin(FileInfo pluginFile) in /Users/simon/Projects/Hermod/Hermod/PluginFramework/PluginRegistry.cs:line 83
    10. at Hermod.Hermod.HandleLoadPlugin(String[] args) in /Users/simoncahill/Projects/Hermod/Hermod/Hermod.Commands.cs:line 111
    11. System.TypeLoadException: Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
    12. System.TypeLoadException: Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
    13. System.TypeLoadException: Could not load type 'System.Data.SqlClient.SqlDataReader' from assembly 'System.Data.SqlClient, Version=4.6.1.5, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.


    Als kleine Randbemerkung:

    Wenn du tatsächlich in ​UnhandledException reinläufst, kann es durchaus sein, dass deine Applikation in einem instabilen Zustand ist!
    Es ist nicht ratsam, dort noch großartig zu versuchen, die Applikation am Leben zu halten.

    Es kann gutgehen, muss aber nicht - ich spreche da leider aus Erfahrung :D

    Am besten versuchst du noch zu retten, was zu retten ist und forderst deinen Benutzer auf, die Applikation neu zu starten; ggf. noch Logpfade usw. anzeigen oder einen automatischen Reporter starten.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    siycah schrieb:

    Es ist nicht ratsam, dort noch großartig zu versuchen, die Applikation am Leben zu halten.
    Ich glaube sogar, dass das gar nicht geht.
    Man kann nur ein Maximum an Information speichern und sauber beenden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Ich glaube sogar, dass das gar nicht geht.


    Doch doch, das geht.

    XML-Quellcode

    1. <configuration>
    2. <runtime>
    3. <legacyUnhandledExceptionPolicy enabled="1" />
    4. </runtime>
    5. </configuration>


    Fügt man das in die Application.config ein, kann man die Applikation weiter ausführen lassen.

    Nichtsdestotrotz ist es nicht ratsam, sowas zu versuchen.

    In C++ (unter Linux) kann man das Ganze sogar noch weiter treiben. Wir haben da auch schon mit verrückten Sachen experimentiert, dass wir die Applikationen einfach während der Laufzeit ersetzt haben und den internen Status weitergegeben haben - das war schwer zu debuggen, wenn es dann beim dritten oder vierten mal endgültig wegen irgendwelcher ungültigen Speicherzugriffe geknallt hat.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    siycah schrieb:

    Nichtsdestotrotz ist es nicht ratsam, sowas zu versuchen.
    Versuchen schon, allerdings nicht in der Version für den Kunden.
    Ich halte es für sehr wichrtig, solche Sachen mal durch zu exerzieren, in einem Projekt habe ich sogar einen Compilerschalter, wo gezielt an kritischen Stellen Exceptions geschmissen werden, um sie zu vermeiden bzw. um sie an den richtigen Stellen abzufangen, damit das Programm nicht abschmiert.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    An Coldfire:

    werden in dem geschriebenen Programm Aufgaben (insbesondere die ein Dictionary betreffen) aus anderen Threads heraus - z.B. mit Async/Await, Task, BGWorker oder Thread - erledigt?
    Das gleichzeitige Erscheinen von Dummheit und Unmündigkeit nach Immanuel Kant ist eines der schlimmsten Dinge, die einem Homo sapiens in geistiger Hinsicht widerfahren können, hat manchmal aber auch durchaus seine Vorteile.

    RodFromGermany schrieb:

    habe ich sogar einen Compilerschalter, wo gezielt an kritischen Stellen Exceptions geschmissen werden, um sie zu vermeiden bzw. um sie an den richtigen Stellen abzufangen, damit das Programm nicht abschmiert.


    Ja, würde ich unterschreiben, dass das wichtig ist. Allerdings braucht man nicht versuchen, eine instabile Anwendung am Laufen zu erhalten.
    In dem Fall alle Informationen sammeln und dann weiter debuggen. Jetzt weiß ich allerdings nicht, ob .net ein Feature wie Coredumps hat. Das wäre natürlich noch besser; beim Absturz ein Coredump generieren und zum Entwickler schicken.

    Direkt im Debugger mit Coredump starten und den genauen Zustand der Anwendung nachstellen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    siycah schrieb:

    eine instabile Anwendung
    Hier war nicht die Anwendung instabil, sondern die auszuweretenden Daten waren Mist. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also ich verwende eine ganze Menge Zeugs in meinem Code, auch BGWorker , Threading, dll-calls usw. Der beobachtete Effekt tritt sowohl bei mir als auch bei anderen Rechnern auf. Der Effekt ist auch eher sporadisch als fest reproduzierbar. Da die Verwendung des Programms aber an sich komplex ist und dann noch mit anderen kompexen Programmen kooperiert, ist ein reproduzieren oft nicht möglich. Der Effekt ist unabhängig ob debug oder relase aktiv ist. Ich habe ein mehrstufiges Logging implementiert, das ist aber nicht sehr hilfreich: ich müsste es auf Verdacht laufen zu lassen, wodurch Tonnen von sinnlosen Protokollen erzeugt werden, sehr umständlich. Besonders weil das ja überhaupt nicht das Problem ist. Die Exception ist ja protokolliert. Nur seltsamerweise in der Ereignisanzeige und nicht per Meldung.
    Ich würde euch jetzt explizit bitten, mal in euerer Ereignisanzeige nachzusehen, ob ihr auch .net exceptions da findet. Meine aktuelle Arbeitshypothese ist, dass das GDI abgeschmiert ist und kein windows-handle mehr erzeugen kann. Ergänzung: es ist eine Windows Forms Anwendung.

    Coldfire schrieb:

    dass das GDI abgeschmiert ist
    Das kommt mir bekannt vor.
    Hier ist manchmal beim Dateizugriff mit falschem Pfad die Ursache.
    Aber das passt nicht zu den sonstigen Informationen von Dir.
    Möglicherweise knallt auch eine API, die kann nicht so einfach abgefangen werden.
    Wie sieht Dein globales Exceptionhandling aus?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Coldfire schrieb:

    ich müsste es auf Verdacht laufen zu lassen, wodurch Tonnen von sinnlosen Protokollen erzeugt werden


    Wenn du rolierende Logs verwendest, ist das gar kein Problem. Dann sagste dass die Logs einmal am Tag rolieren sollen und/oder dass sie eine max. Größe von XMiB haben.

    RodFromGermany schrieb:

    Möglicherweise knallt auch eine API, die kann nicht so einfach abgefangen werden.


    Würde mich allerdings auch interessieren, welche (Windows-?)APIs aufgerufen werden.

    @Coldfire Wenn du C-APIs aufrufst, geben die meist ein ​int als Returnwert zurück. Bei den allermeisten solchen APIs wird Nicht-0 zurückgegeben, wenn ein Fehler aufgetreten ist und dann wird ​errno gesetzt. Falls du solche APIs in deinem Code verwendest, kannst du folgendes verwenden:

    C#-Quellcode

    1. [DllImport("meine.dll", SetLastError = true, CharSet = CharsSet.Unicode)]
    2. public static extern int ExterneFunc();
    3. void Foo() {
    4. int x = ExterneFunc();
    5. var lastError = Marshal.GetLastWin32Error();
    6. if (lastError != 0) {
    7. // Fehler ist aufgetreten
    8. // mit strerror() ausgeben
    9. }
    10. }
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)

    Coldfire schrieb:

    Also ich verwende eine ganze Menge Zeugs in meinem Code, auch BGWorker , Threading, dll-calls usw. Der beobachtete Effekt tritt sowohl bei mir als auch bei anderen Rechnern auf. Der Effekt ist auch eher sporadisch als fest reproduzierbar (...)

    Ist eine gute Mischung, um unterwegs beim Schreiben oder spätestens am Ende den Überblick - was, wo, wie und wann passiert bzw. abgearbeitet wird - zu verlieren. Hat man wenigstens bei solchen Dingen wie Dictionary, Queue & Co. statt der normalen 0815-Dinger die Luxusvariante, d.h. die threadsicheren Pendants genommen? Sie heißen auch anders und sind deutlich schwieriger in der Handhabung bzw. etwas umständlicher zu bedienen, aber damit hätte man dann wenigstens schon mal eine Fehlerquelle weniger bei der Suche, wenn das, was Microsoft in diesem Kontext verspricht, tatsächlich bis ins kleinste Detail auch wahr ist - die Wahrscheinlichkeit ist aber sehr groß, dass das stimmt, was da so gepredigt und versprochen wird. Dann gibt es noch die üblichen Zugriffe bei Multithreading - z.B. lesen-schreiben oder schreiben-schreiben einer Speicherlokation oder eines Objekts von zwei verschiedenen Stellen/Threads/Akteuren. Das erste wäre unter Umständen noch OK, das zweite nicht mehr, man müsste hier einen speziellen Mechanismus in den Code einbauen - und zwar überall im Code, wo darauf zugegriffen wird - damit wirklich niemals etwas passiert. So etwas im Nachhinein einzubauen ist gar nicht so trivial, da man ja schon so viel geschrieben, zwischendurch auch mal fremdes Zeug verwendet und meistens diesen schönen Überblick nicht mehr hat oder gar nicht haben kann.
    Das gleichzeitige Erscheinen von Dummheit und Unmündigkeit nach Immanuel Kant ist eines der schlimmsten Dinge, die einem Homo sapiens in geistiger Hinsicht widerfahren können, hat manchmal aber auch durchaus seine Vorteile.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Gregor Jasinski“ ()

    Gregor Jasinski schrieb:

    Ist eine gute Mischung, um unterwegs beim Schreiben oder spätestens am Ende den Überblick - was, wo, wie und wann passiert bzw. abgearbeitet wird - zu verlieren


    Das ist nett, nochmal so die Basics von Multithreading von dir zu hören, nur mir fehlt mir da irgendwie der Zusammnhang zu meinem Post. Wenn du Probleme hast, den Überblick zu behalten, dann helfe ich dir gerne.

    zu siycah: Die Frage ist, ob unhandled exceptions nicht verlässlich sind, also müsste man praktisch in alle Routinen ein excetion handling einbauen, was ich bisher nur bei weniger als 50 Fällen implementiert habe. Also weniger als 1%. Macht ihr das auch so?
    Und der gdi-Absturz findet ja nicht in meinem Code statt, denn System.Collections.Generic.KeyNotFoundException hat meines Wissens nichts mit GDI zu tun. Ich wiederhole : das Problem ist dass diese Exception mal ganz normal eine Exception-Meldung ausgibt, und in anderen Fällen eben nicht, das Programm beendet sich ohne Meldung.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Coldfire“ ()

    Coldfire schrieb:

    Wenn du Probleme hast (...)

    Ich glaube, die Probleme hast momentan Du, mit Deiner Anwendung, weil man höchstwahrscheinlich solche „Basics” nicht beachtet hat.
    Das gleichzeitige Erscheinen von Dummheit und Unmündigkeit nach Immanuel Kant ist eines der schlimmsten Dinge, die einem Homo sapiens in geistiger Hinsicht widerfahren können, hat manchmal aber auch durchaus seine Vorteile.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Gregor Jasinski“ ()

    Coldfire schrieb:

    Die Frage ist, ob unhandled exceptions nicht verlässlich sind, also müsste man praktisch in alle Routinen ein excetion handling einbauen
    Unhandled Exceptions sind zu 99% verlässlich.
    Wenn da bei einem extrem seltenen Spezialfall Mist passiert, sollte man keinesfalls anfangen, systematisch die gesamte Codelandschaft mit sinnlosen und sogar gefährlichen TryCatches zu verpflastern.

    Du hast da halt ein lausiges Problem, und musst debuggen irgendwie. Vielleicht können Trycatches da iwas helfen, meinetwegen auch viele.
    Aber wenn du den Fehler gefunden und gefixt hast, dann bau sie um Himmelswillen wieder weg.
    @ErfinderDesRades Nicht ganz.
    @Coldfire In der Release ist das Abfangen von Unhandled Exceptions dahingehend sinnvoll, damit der Kunde ein "vernünftiges" Programm-Ende-Szenario bekommt und Euch die erforderlichen Informationen zukommen lassen kann.
    In der Debug solltest Du Exceptions weitestgehend vermeiden. Und wenn, dann fange genau die Exception ab, die Du abfangen willst/musst, nicht aber pauschal alle.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!