OnError-Include [PB4.x]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
freak
PureBasic Team
Beiträge: 766
Registriert: 29.08.2004 00:20
Wohnort: Stuttgart

Beitrag von freak »

> Gerade bei sporadischen Fehlern die ab und zu auftauchen sollte es möglich sein das Programm weiter laufen zu lassen denke ich.

Genau diese "lassen wir es mal weiterlaufen, es wird schon nichts passieren" Einstellung war mit ein Grund warum das jetzt nicht mehr geht.

> Schau dir mal andere Sprachen an, die haben auch Exeption Handler und da wird auch nicht einfach das Programm geschlossen wenn ne Exeption aus´gelöst wird oder?

Diese haben dann aber auch "echtes" Exception handling, mit try/catch usw, damit der Compiler auch wirklich weiß was zu tun ist um nach dem Fehler aufzuräumen. PB musste bisher im Prinzip "raten" wo die Ausführung denn fortgesetzt werden soll und selbst wenn das dann geklappt hat dann ist immernoch nicht das Problem gelößt das der Fehler ja irgendwelche Daten
in einem Zustand belässt das sie nicht zu gebrauchen sind. Das Ergebnis ist also ein direkter Folgefehler. Und selbst wenn das dann auch nicht passiert dann rechnet dein Programm mit einem falschen Wert weiter, und macht dann irgendwas unvorhersebares damit. Sehr schöne Vorstellung

> Naja bei Division von null ist es z.b. nicht nötig das Programm gleich ganz zu schliessen.

Da liegst du meiner Meinung nach falsch. Die Division hatte ja irgendeinen Sinn. Der Wert der da berechnet wurde wird ja später irgendwo gebraucht. Wenn du das Programm einfach fortsetzt sagst du praktisch "scheiß drauf, lass uns einfach mit einem Zufälligen Wert weiterrechnen. Wird schon nichts passieren". Was würdest du davon halten wenn der PB Compiler Befehle in dein Programm einbaut die einfach zufällig die Werte von Variablen ändern ? Genau das bekommst du aber wenn du das Programm nach einem Fehler fortsetzt.

> Ich finds schon recht komisch und schade das dieser weg jetzt eingeschlagen wurde.

Der Sinn der OnError lib ist es, Fehler die sonst das Programm direkt beenden abzufangen, Informationen zu dem Fehler zu sammeln und eventuell noch wichtige Daten zu sichern und dann das Programm zu beenden. Der Sinn liegt nicht darin das man einfach schwehrwiegende Programmfehler einfach ignoriert. Schließlich gibt es ja einen guten Grund warum das OS das Programm direkt beendet ohne OnError lib. Wenn das alles kein Problem wäre dann wäre ja auch das nicht nötig.

Die OnError Lib ist dazu da Fehler zu finden und zu beheben, nicht sie zu ignorieren.
Benutzeravatar
nicolaus
Moderator
Beiträge: 1175
Registriert: 11.09.2004 13:09
Kontaktdaten:

Beitrag von nicolaus »

@freak

Erstmal danke für die Erklärung.

Wird es denn mal ein "echtes" Exeption-Handling geben so wie von dir angesprochen?

Gruß,
Nico
freak
PureBasic Team
Beiträge: 766
Registriert: 29.08.2004 00:20
Wohnort: Stuttgart

Beitrag von freak »

Ich denke eher nicht.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

freak hat mit seinen obigen Darlegungen absolut Recht, aber aus Jux trotzdem folgender Code, der evtl. als Anregung für eigene Experimente dienen kann:

Code: Alles auswählen

;Thread-Exception-Handler (TEH). Nutzt die Tatsache, dass die Exception-Handler-Zeiger eine Art
; Linked-List bilden, deren Beginn der Anfang des F-Segmentes ist. TEH deshalb, weil so nicht nur
; für den Prozess, sondern für jeden Thread ein eigener TEH erstellt werden kann. 
;Division durch Null soll hier nur das Prinzip zeigen, eine Programm-Fortsetzung danach wäre praktisch
; natürlich (meist) Unfug, hängt aber sicher auch von der (eigenen) Behandlungs-Routine ab.  
;Benötigt kein Einschalten der OnError-Unterstützung
;Es lassen sich auch z.B. die Debug-Register (Drx) anzeigen und auswerten
;PB 4.30 Beta 5, Win XP, Demo, "Helle" Klaus Helbing, 14.12.2008

Global X.i                   ;"Universal-" Variable 

;diese 4 Zeilen biegen den Zeiger auf den (die) Exception-Handler auf eine eigene Routine um 
!lea esi,[TEH]               ;Zeiger auf den eigenen Exception-Handler
!push esi                    ;auf den Stack schieben
!push dword ptr fs:0         ;Zeiger auf jetzt nächste Exception-Handler-Struktur
!mov [fs:0], esp             ;neuer Anfang der Exception-Handler-Liste
;-------------------------------------------------------------------------------------------

;!push 12345                  ;für Stack-Test

;dies ist der PB-Programm-Code, hier nur für Exception-Erzeugung
A / B                        ;Fehler erzeugen, Division durch Null
;---------------------------------------------------------------

;!pop [v_X]                   ;für Stack-Test

;hier geht´s nach der Exception weiter
MessageRequester("Weiter", "Programm-Fortsetzung nach einer Exception");    "+ Str(X)) ;X muss hier wieder 12345 sein
;-------------------------------------

End 

;----------------------------------------------------------------------------------------
!TEH:
!mov ebx,[esp+4]             ;Zeiger auf EXCEPTION_RECORD-Structure
!mov [v_X],ebx
*ER.EXCEPTION_RECORD = X     ;Structure EXCEPTION_RECORD

!mov ebx,[esp+12]            ;Zeiger auf CONTEXT-Structure
!mov [v_X],ebx
*CON.CONTEXT = X             ;Structure CONTEXT

;den verursachenden ASM-Code ermitteln, Lizenz beachten!
ExamineAssembly(*ER\ExceptionAddress)
NextInstruction()
ASM$ = "ASM-Code an dieser Adresse: " + UCase(InstructionString())

;Register-Werte zum Exception-Zeitpunkt auslesen, hier mit Debug-Register
Reg$="Register-Werte zum Exception-Zeitpunkt :"+#LFCR$
Reg$+"DR0 = $"+Hex(*CON\Dr0)+#LFCR$+"DR1 = $"+Hex(*CON\Dr1)+#LFCR$+"DR2 = $"+Hex(*CON\Dr2)+#LFCR$
Reg$+"DR3 = $"+Hex(*CON\Dr3)+#LFCR$+"DR6 = $"+Hex(*CON\Dr6)+#LFCR$+"DR7 = $"+Hex(*CON\Dr7)+#LFCR$
Reg$+"EAX = $"+Hex(*CON\Eax)+#LFCR$+"EBX = $"+Hex(*CON\Ebx)+#LFCR$+"ECX = $"+Hex(*CON\Ecx)+#LFCR$
Reg$+"EDX = $"+Hex(*CON\Edx)+#LFCR$+"EDI = $"+Hex(*CON\Edi)+#LFCR$+"ESI = $"+Hex(*CON\Esi)+#LFCR$
Reg$+"EBP = $"+Hex(*CON\Ebp)+#LFCR$+"ESP = $"+Hex(*CON\Esp)+#LFCR$+"EIP = $"+Hex(*CON\Eip)+#LFCR$
;bei Bedarf mehr

Select *ER\ExceptionCode
  Case #EXCEPTION_INT_DIVIDE_BY_ZERO   ;hier nur diese Auswertung
    Error$ = "Integer-Division durch Null" + #LFCR$ + "ExceptionCode : $" + Hex(*ER\ExceptionCode, #PB_Long) + #LFCR$
    Error$ + "Fehler-Adresse in der EXE : $" + Hex(*ER\ExceptionAddress) + #LFCR$ + ASM$ + #LFCR$ + Reg$
  ;Case ... 
  ;hier dann weitere Exceptions
EndSelect

MessageRequester("Fehlerauswertung :", Error$)

;hier könnten Auswertungen und Reaktionen folgen
 
;hier aus Jux auf Fortsetzungs-Möglichkeit des Programmes testen
If *ER\ExceptionFlags        ;wenn Null, ist zumindest das Betriebssystem nicht angekratzt
  End                        ;Windows meint, jetzt muss Schluss sein
EndIf

;kühn setzen wir fort
;Register restaurieren
X = *CON\Eax : !MOV eax,[v_X]
X = *CON\Ebx : !MOV ebx,[v_X]
X = *CON\Ecx : !MOV ecx,[v_X]
X = *CON\Edx : !MOV edx,[v_X]
X = *CON\Edi : !MOV edi,[v_X]
X = *CON\Esi : !MOV esi,[v_X]
X = *CON\Ebp : !MOV ebp,[v_X]
X = *CON\Esp : !MOV esp,[v_X]

NextInstruction()
X = InstructionAddress()
!jmp [v_X]                   ;jaja, sollte aber so gehen
Gruß
Helle
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Naja, viele Anti-Debugger Tricks basieren auf Auslösung von Exceptions. Kann man natürlich auch mit inline Assembler machen. Sieht aber dann irgendwie unschön aus.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
nicolaus
Moderator
Beiträge: 1175
Registriert: 11.09.2004 13:09
Kontaktdaten:

Beitrag von nicolaus »

Helle hat geschrieben:freak hat mit seinen obigen Darlegungen absolut Recht, ....
Naja das sehe ich noch immer anders denn ich möchte eigentlich nicht das PB entscheidet wann mein Programm geschlossen wird.

So viel vertrauen sollte PB den Entwicklern schon schenken das sie selber entscheiden bei welchem Fehler das Programm geschlossen wird und bei welchem es noch weiter laufen kann.

Von daher find ich es schon extrem schade das die Möglichkeit das Programm weiter laufen zu lassen weg razionalisiert wurde.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Nur, wenn´s nicht funktioniert schiebst du es PB in die Schuhe. Deshalb mein Verständnis dafür, dass freak auf Nummer gehen will. Mit meinem obigen Code kannst du doch einen eigenen Exception-Handler bauen (sogar etwas, was den Namen SEH verdient).

Gruß
Helle
Little John

Beitrag von Little John »

Ich kann freaks Standpunkt voll und ganz verstehen, und begrüße die Entscheidung das jetzt so zu machen ausdrücklich.

Gruß, Little John
freak
PureBasic Team
Beiträge: 766
Registriert: 29.08.2004 00:20
Wohnort: Stuttgart

Beitrag von freak »

> Von daher find ich es schon extrem schade das die Möglichkeit das Programm weiter laufen zu lassen weg razionalisiert wurde.

Wie ich in meinem ersten posting erwähnt hatte gab es mehr Gründe als nur "Wegrationalisierung".

Wie bereits erwähnt muss die Lib die Adresse der nächsten Instruktion zum Ausführen finden, weil einfaches Ausführen an der alten Stelle ja die gleiche Instruktion die den Fehler verursacht hatte einfach nochmal ausführen, also den Fehler wiederholen würde. Die x86 (und auch x64) Architektur hat variable Instruktionsgrößen, man muss also die Instruktion vollständig decodieren um zu erfahren wo die nächste anfängt. Hierfür hatte Rings für die alte Lib einen x86 Disassembler geschrieben (komplett in Asm)

Mit 4.30 gibt es aber PureBasic auch für x64 und diesen Disassembler auf x64 zu portieren (und um die x64 Befehle zu erweitern) wäre eine Unmenge an Arbeit gewesen. Und ich wage auch zu bezweifeln ob das Ergebnis wirklich Fehlerfrei funktioniert hätte :). Assemblercode dieser Größe (den man auch nicht selbst geschrieben hat) zu portieren ist die Hölle. Ich weiß wovon ich reden denn ich habe damals die komplette Gadget lib von Asm nach C portiert. Aus diesem Grund verwenden die neuen Disassembler Befehle die libudis86, welche x86 und x64 unterstützt (inklusive der Befehlssatzerweiterungen die die PB lib auch nicht konnte), aber eben unter der BSD Lizenz steht. Das ist von der Verwendung her keine wirkliche Einschränkung, aber jeder der die Befehle benutzt muss die Lizenz von libudis86 in seine Programmdokumentation aufnehmen.

Kommen wir zurück zu OnErrorCall(): Wenn OnErrorCall() auch libudis86 zur Decodierung der aktuellen Instruktion verwenden würde, dann wäre jeder PB User der die OnError lib verwendet gezwungen die Lizenz seinem Produkt beizulegen, selbst wenn er gar nicht vor hat das Programm vortzusetzen. Diese Bürde wollten wir den Usern einfach nicht auferlegen nur für ein Feature was nicht wirklich zuverlässig und auch nicht wirklich sinnvoll ist. Willst du, nicolaus, etwa der Buhmann sein wegen dem jeder User der OnError lib dazu gezwungen wird ? :wink:

Ich finde es wirklich schade das einige User in solchen Fällen einfach annehmen das solche Dinge aus reiner Boshaftigkeit oder Faulheit passiert sein mussten und erstmal losmeckern ohne nach den wahren Gründen zu fragen. (Zitat "mal wieder eins von Freds sinnlosen undingern") Solche Entscheidungen fallen bei uns nie aus dem Bauch herraus, das könnt ihr mir glauben.

Seht es mal von der anderen Seite:
Mit 4.30 habt ihr eine OnError lib, die von OSX ppc bis Windows x64 auf allen aktuellen PB Platformen vollständig funktioniert. Dafür habe ich eine Menge Arbeit investiert (ich sag nur x64 Exception handling *würg*). Der Preis dafür ist das ein (mehr oder weniger fragwürdiges) Feature nicht weiter unterstützt werden kann. Das ist doch wirklich ein kleiner Preis. Und wie bereits gesagt, wer es wirklich braucht kann die Lib von 4.20 weiter verwenden, ist dann aber auf Windows x86 festgelegt.
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Hier kann ich nur sagen "Danke für die viele Arbeit".

Ein Programm zu schreiben welches alle erforderlichen Funktionen erfüllt ist eine sache.
Aber ein Programm zu schreiben welches auch sämtliche Bedien und Eingabefehler von den Benutzern abfängt ist immer mit erheblich grösseren aufwand verbunden.
Leider machen sich viele nicht diese Arbeit.

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten