Laden...

Exception trotz try-catch

Erstellt von PierreDole vor 2 Jahren Letzter Beitrag vor 2 Jahren 396 Views
P
PierreDole Themenstarter:in
74 Beiträge seit 2017
vor 2 Jahren
Exception trotz try-catch

Moin,

ich habe mir ein Open-Source-Projekt runtergeladen und bekomme da ab und zu eine Exception geworfen. Dachte, ich packe einfach an der Stelle einen try-catch Ausdruck und gut ist. Leider funktioniert das nicht. 🙂 Da ich selber eigentlich sehr selten try-catch benutze, tue ich mir gerade etwas schwer das richtig zu setzen.

Der Ausnahmefehler kommt immer bei return a, ob mit oder ohne try.

Im Original sieht die Methode wie folgt aus:


public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                return a;
            }

            return default;
        }

Das ist mein try-catch Versuch:


public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                try
                {
                    IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                    ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                    return a;
                }
                catch(System.AccessViolationException e)
                {
                    System.Console.WriteLine(e.Message);
                    return default;
                }
            }

            return default;
        }

Ist das so richtig?

Edit:
Habe die Exception ganz vergessen.
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. Dann der Verweis auf die Zeile mit return a.

16.806 Beiträge seit 2008
vor 2 Jahren

Welche Exception bekommst Du? Nicht alle Exceptions kann man abfangen, zB MemoryExceptions.
Bitte Fehlermeldungen im Original posten, siehe [Hinweis] Wie poste ich richtig?

P
PierreDole Themenstarter:in
74 Beiträge seit 2017
vor 2 Jahren

Sorry, mein Edit und Dein Post haben sich überschnitten.

Wenn man MemoryExceptions nicht abfangen kann, gibt es dann wenigstens eine Möglichkeit zu überprüfen, ob auf jene Stelle im Memory gerade zugegriffen werden kann?

2.078 Beiträge seit 2012
vor 2 Jahren

Steht doch in der Doku: AccessViolationException Class (System)

2.078 Beiträge seit 2012
vor 2 Jahren

Sorry, mein Edit und Dein Post haben sich überschnitten.

Wenn man MemoryExceptions nicht abfangen kann, gibt es dann wenigstens eine Möglichkeit zu überprüfen, ob auf jene Stelle im Memory gerade zugegriffen werden kann?

Die konkrete Stelle hilft dir nicht weiter, die .NET Runtime schaufelt doch immer hin und her - solltest Du das verhindern/umgehen, dann hast Du schon deinen Fehler 😉
Und ich denke, Abt meint die OutOfMemoryException. Wann die geworfen wird, steht in der Doku und dann hat man nicht nur irgendeine Stelle im RAM.

16.806 Beiträge seit 2008
vor 2 Jahren

Und ich denke, Abt meint die OutOfMemoryException.

Der Abt meint mehrere Exceptions.
Alle Exceptions, die laut .NET auf einen "corrupted state" des Prozesses hinweisen, darunter AccessViolationException und OutOfMemoryException.. können nicht gefangen werden.

P
PierreDole Themenstarter:in
74 Beiträge seit 2017
vor 2 Jahren

Habe ich das richtig verstanden, daß wenn ich das Attribut [HandleProcessCorruptedStateExceptions] hinzufüge, dann sollte die Exception gecatcht werden? Leider kann ich die Exception nicht ohne Weiteres rekonstruieren und überprüfen ob es jetzt klappt. Die wird einfach ab und zu geworfen.

Ist das so richtig?


[HandleProcessCorruptedStateExceptions]
        public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                try
                {
                    IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                    ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                    return a;
                }
                catch(System.AccessViolationException e)
                {
                    System.Console.WriteLine(e.Message);
                    return default;
                }
            }

            return default;
        }

16.806 Beiträge seit 2008
vor 2 Jahren

Die Exception ist im Endeffekt ein Hinweis, dass Du womöglich einen Fehler beim Speicherzugriff hast.
Du solltest also die Ursache korrigieren, nicht die Exception.

HandleProcessCorruptedStateExceptions greift nur in NetFX Projekten. Der Prozess selbst bleibt aber "corrupt".
In .NET Core bzw. .NET 5 und höher gibts das Attribut auch; macht aber nichts. Existiert nur noch aus Kompatibilitätsgründen.

4.931 Beiträge seit 2008
vor 2 Jahren

@PierreDole: Die Addressberechnung (bzgl. graphic) erscheint mir auch eigenartig, besonders graphic >> 3, was ja graphic / 8 bedeutet (ausmultipliziert kommt da m.E. (graphic * (68 + 1/2) + 4) heraus!?!).

P
PierreDole Themenstarter:in
74 Beiträge seit 2017
vor 2 Jahren

@Abt:
Ja, das ist etwas komplizierter, als ich es anfangs beschrieben habe. Die eigentliche Ursache liegt in einem Plugin. Ohne das Plugin wurde die Exception nicht geworfen. Irgendwo beißen sich die beiden unter bestimmten Umständen. Nun, das Plugin ist einerseits auch open-source, andererseits hat es mehrere Hundert Klassen. Da die Exception auf den Client verweist, weiß ich nicht wo ich im Plugin suchen sollte. Alleine das Einlesen würde Wochen dauern, die Fehlersuche womöglich Monate.
Von daher ist es jetzt für mich das Naheliegendste die Exception zu umgehen, da die Methode eh nur zur Berechnung einer Amimation von Spielfiguren dient. Ich kann damit leben, wenn mal eine Figur eine Animation nicht mitmacht. Nur der Client sollte nicht dabei crashen. 🙂

@Th69:
Ehrlich gesagt: keine Ahnung. 🙂 Mit Memory und Pointern habe ich mich noch nicht auseinandergesetzt. Ich weiß nur, daß der >>-Operator irgendwas mit verschieben bedeutet, aber ausrechnen und/oder überprüfen kann ich die Rechnung im Code nicht.

4.931 Beiträge seit 2008
vor 2 Jahren

Woher hast du denn diese Formel? Bist du dir bei der 68 sicher (oder soll es 64 heißen)?

Du kannst dir doch (zum Test) jedesmal die Adressen ausgeben lassen:


Console.WriteLine($"{graphic}: {addr}");

Dann weißt du zumindestens, bei welchen Werten es crasht (letzte Zeile der Konsolenausgabe).

Bei Unsafe-Programmierung mußt du dir aber 100%ig sicher sein (ist ja, also ob man direkt C oder C++ programmiert) - jeder Speicherzugriffsfehler führt zum Crash!

P
PierreDole Themenstarter:in
74 Beiträge seit 2017
vor 2 Jahren

Ich habe das nicht programmiert, ich benutze es nur. 🙂 Es ist ein open-source Client für das uralte Ultima Online, geschrieben in C#. ClassicUO nennt er sich und das Plugin, das ich dazu benutze, ist der ClassicAssist.

16.806 Beiträge seit 2008
vor 2 Jahren

Woher hast Du es denn dann, gib ma paar Infos und lass uns nich raten 🙂
Speicherzugriffsfehler in Prozessen führen i.d.R. immer zum Crash, daher muss man sie vermeiden, ++bevor ++sie auftreten.

4.931 Beiträge seit 2008
vor 2 Jahren

OK, danke für den Github-Link. Die Formel scheint wohl richtig zu sein, sie wird ja 2x benutzt (in src/IO/Resources/AnimDataLoader.cs sowie src/Game/Managers/AnimatedStaticsManager.cs (hier sogar als / 8 geschrieben).