Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Try-Except Raise funktioniert nicht richtig
schippi - Mo 22.10.07 11:16
Titel: Try-Except Raise funktioniert nicht richtig
Hallo, bei folgendem Programmcode funktioniert Try-Except nicht richtig.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| Var Sum: PByte; Size: Integer; Begin Size := 2147483646; GetMem(Sum, Size);
try FillChar(Sum^, Size, 0); except showmessage('Blabla'); end; End; |
Hier tritt bei FillChar eine Access Violation auf. Wieso springt das Programm nicht in except :?:
Was bei mir ebenfalls nicht funktioniert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| Try a:=1/0; except showmessage('Test'); raise Exception.Create('Beispiel-Exception'); End; |
es wird except einfach übersprungen. Wenn ich es aber ein klein wenig ändere, dann springt das Programm in except und zeigt die Meldung 'Test' an, aber die Meldung 'Beispiel-Exception' wird nicht angezeigt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| Try a:=1; a:=a/0; except showmessage('Test'); raise Exception.Create('Beispiel-Exception'); End; |
Also ich steh aufm Schlauch... :autsch:
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt
Alpha_Wolf - Mo 22.10.07 11:28
Anstelle von E:Exception kannst du alle Arten von Exceptions hernehmen. Mit E:Exception fängst du alle ab. Du kannst aber auch auf bestimmte eingehen wie in deinem Fall auf die EAccessViolation und darauf speziell reagieren. Raise musst du gar nicht aufrufen! Nimm einfach ein ShowMessage oder eine MessageBox mit dem jeweiligen Messagetyp.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| try except on E:Exception do begin end; end; |
Marc. - Mo 22.10.07 11:29
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| try GetMem(Sum, Size); FillChar(Sum^, Size, 0); except showmessage('Blabla'); end; End; |
Da bereits in GetMem(); eine EOutOfMemory-Exception auftritt, solltest du diese auch mit in den Block nehmen. ;)
grüße,
Marc
Alpha_Wolf - Mo 22.10.07 11:34
Marc. hat folgendes geschrieben: |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| try GetMem(Sum, Size); FillChar(Sum^, Size, 0); except on E:EOutOfMemory do begin showmessage('Blabla'); end; end; End; |
|
Sonst gibt die App die Exception aus und danach deine Showmessage..
Narses - Mo 22.10.07 11:46
Moin!
Auch sehr praktisch: ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| try GetMem(Sum, Size); FillChar(Sum^, Size, 0); except ShowMessage(Exception(ExceptObject).Message); end; |
cu
Narses
schippi - Mo 22.10.07 11:47
Hab jetzt alles probiert, was ihr mir empfohlen habt. Aber klappt bei mir immer noch net - ist immer noch so wie´s am Anfang war.
Alpha_Wolf - Mo 22.10.07 12:08
Dann zeig mal deinen modifizierten Code.. hast du auch wirklich das "on E:Exception do begin end;" mit eingabracht im "except" Teil?
Nur Fehler die im Try-Block auftreten werden auch im Except-Block behandelt. Alles andere wird nicht abgefangen.
schippi - Mo 22.10.07 12:27
Hab mal ein neues Projekt erstellt und nur mal die verschiedenen Codestellen ausprobiert. Da hat komischerweise alles funktioniert.
Dann hab ich mein anderes Projekt genommen,das wenn ich nicht absichtlich einen Fehler provoziere, einwandfrei funktioniert. Nur wenn ich dann folgenden Code reinkopiere, gehts wieder net.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Size := 2147483646; Try GetMem(Sum, Size); FillChar(Sum^, Size, 0); Except On E: EOutOfMemory Do Begin showmessage('Blabla'); End; End; |
Es kommt wieder beim FillChar des blöde Access Violation und nicht mein 'BlaBla' :bawling:
Marc. - Mo 22.10.07 12:30
Bei mir funktioniert dein Code wunderbar. :roll:
Narses - Mo 22.10.07 12:31
Moin!
schippi hat folgendes geschrieben: |
Es kommt wieder beim FillChar des blöde Access Violation und nicht mein 'BlaBla' :bawling: |
Zunächstmal ist mir zwar schleierhaft, wozu man einen 2GB RAM-Block anfordern sollte (was auf jeder Win32-Maschine nicht klappen sollte...), aber nun gut. :?
Probier das nochmal so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| Size := 2147483646; Try GetMem(Sum, Size); if Assigned(Sum) then FillChar(Sum^, Size, 0); Except ShowMessage(Exception(ExceptObject).Message); End; |
cu
Narses
schippi - Mo 22.10.07 12:35
Mir fällt gerade noch ein, ich benutz in dem Projekt auch die TNBFPA-Socket Komponente von Narses. Ich glaub da werden die Fehlermeldungen irgendwie anders abgefangen. Kann das was mit meinem Problem zu tun haben?
Narses - Mo 22.10.07 12:46
Moin!
schippi hat folgendes geschrieben: |
Mir fällt gerade noch ein, ich benutz in dem Projekt auch die TNBFPA-Socket Komponente von Narses. Ich glaub da werden die Fehlermeldungen irgendwie anders abgefangen. Kann das was mit meinem Problem zu tun haben? |
Kommt darauf an, wo die Exception auftritt. Wenn du innerhalb der
OnExecute-Methode eine Exception produzierst, dann wird das über die
OnError-Methode abgewickelt, und nicht als Exception. :idea: (Steht aber auch genau so in der Doku! :les: ;) )
Aber ohne den Code zu kennen, kann ich nicht mehr dazu sagen. :nixweiss:
cu
Narses
schippi - Mo 22.10.07 12:46
Hallo Narses!
Den 2 GB Ram-Block benutz ich ja nur um die Exception auszuprobieren. Sonst natürlich net.
Der Code funktioniert auch nicht in meinem Projekt. Kann das was mit deiner Komponente zutun haben? Weil in einem neuen Projekt funktionierts ja...
Viele Grüße
Schippi
Alpha_Wolf - Mo 22.10.07 12:50
Wenn du dein Programm in deiner Laufzeitumgebung kompilierst und startest dann kommt immer die Exception (außer du stellst sie in den Projektoptionen aus) Starte mal die exe direkt in deinem Zielverzeichnis. Da sollte nur deine Meldung erscheinen.
schippi - Mo 22.10.07 13:08
Erwischt! Ich bin in der OnExcecute-Methode! :oops: Ich hab da wirklich net mehr dran gedacht.
Kann ich trotzdem den Fehler irgendwie abfangen, so dass kein Access violation kommt?
Zitat: |
Alpha_Wolf:
Starte mal die exe direkt in deinem Zielverzeichnis. Da sollte nur deine Meldung erscheinen.
|
Dann wird das Programm einfach beendet ohne irgendeine Meldung.
Narses - Mo 22.10.07 13:29
Moin!
Hier mal der entsprechende Ausschnitt aus dem
TNBFPA-Quelltext (Methode
TProtocolAdapter.ParseStack):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| if Assigned(FOnExecute) then try FOnExecute(FSender,Self); except if Assigned(FOnError) then FOnError(FSender,Self,paeException,Integer(ExceptObject)); end; |
Wie man sieht, werden Exceptions in der
OnExecute-Methode gefangen und an die
OnError-Methode weitergeleitet.
Jetzt kommt es darauf an, was genau passiert ist bzw. wie dein Code aussieht und warum die Exception aufgetreten ist. Es ist IMHO leider keine sonderlich schlaue Idee, mit dem Anfordern eines 2GB-RAM-Blocks einen Fehlerfall zu simulieren, weil Windows nach meiner Erfahrung mit speichermengenbasierten Problemen komische Reaktionen zeigt (und wenn nicht Windows, dann spätestens der Delphi-MemManager). Weiterhin könnte dein Code selbst "komisch" reagieren, wenn die Programmteile nach der Exception - die dann ja nicht durchlaufen werden - irgendwelche Datenstrukturen hätten initialisieren sollen, das aber nicht erfolgt ist und du später versuchst, darauf zuzugreifen. :idea:
Vielleicht solltest du einfach mal mit einer "realistischeren" Fehlersituation testen, da ich den 2GB-RAM-Block-Fall als unrealistisch ausschliessen würde (sowas würde ich schon vor dem Versuch abfangen)... :gruebel:
Weiterhin gilt:
Narses hat folgendes geschrieben: |
Aber ohne den Code zu kennen, kann ich nicht mehr dazu sagen. :nixweiss: |
cu
Narses
schippi - Mo 22.10.07 14:03
So unrealistisch find ich den Code gar net, weil ich hab ja eine Socketverbindung und bekomme einen String gesendet. Zusätzlich bekomm ich noch die Länge des Strings (Size).Würde ich jetzt 10 Zeichen bekommen, wäre Size=10.
Bei einem Übertragungsfehler, könnte der Wert in Size ja plötzlich riesengroß sein(z.B. 235627282). Dann würde ja in dem Code eine Exception ausgelöst werden.
Delphi-Quelltext
1: 2:
| GetMem(Data, Size); FillChar(Data^, Size, 0); |
Oder sollte ich das vielleicht nicht unbedingt mit except abfangen?
Viele Grüße
Narses - Mo 22.10.07 14:09
schippi hat folgendes geschrieben: |
Bei einem Übertragungsfehler, könnte der Wert in Size ja plötzlich riesengroß sein(z.B. 235627282). |
Narses hat folgendes geschrieben: |
sowas würde ich schon vor dem Versuch abfangen |
:les: ;)
schippi - Mo 22.10.07 14:31
Alles klar :wink:
Danke an alle!
Narses - Mo 22.10.07 15:20
Moin!
schippi hat folgendes geschrieben: |
Mir fällt gerade noch ein, |
Mir auch: ;)
schippi hat folgendes geschrieben: |
ich benutz in dem Projekt auch die TNBFPA-Socket Komponente von Narses. |
Die können gar keine größeren Frames als 64KB transportieren; dein "2GB-Problem" ist damit also definitiv (zumindest auf Frame-Ebene des NBFPA) unmöglich. ;)
cu
Narses
schippi - Di 23.10.07 08:05
Hi!
Zitat: |
Die können gar keine größeren Frames als 64KB transportieren; dein "2GB-Problem" ist damit also definitiv (zumindest auf Frame-Ebene des NBFPA) unmöglich.
|
Ich übertrag ja mehrere Frames. Werden beispielsweise 150000 Bytes übertragen, dann ist "size=150000" und die Daten werden halt auf 3 Frames aufgeteilt. Eigentlich sogar 4. Size kommt in einen extra Frame.
Sooo der Plan bis jetzt :wink:
Viele Grüße
alzaimar - Di 23.10.07 08:16
Ihr habt aber -glaube ich- das Problem einfach umschifft, indem ihr sagt: Das kann so nicht passieren. Das mag stimmen, aber die Frage bleibt: Wieso schmiert die Anwendung einfach ab und ist nicht in der Lage, die Exception so zu behandeln, wie sie sollte? :nixweiss:
Narses - Di 23.10.07 12:11
Moin!
alzaimar hat folgendes geschrieben: |
die Frage bleibt: Wieso schmiert die Anwendung einfach ab und ist nicht in der Lage, die Exception so zu behandeln, wie sie sollte? :nixweiss: |
Das sehe ich auch so. ;)
Allerdings habe ich hierzu noch nix weiter gehört, und da vermute ich den Fehler:
Narses hat folgendes geschrieben: |
Weiterhin könnte dein Code selbst "komisch" reagieren, wenn die Programmteile nach der Exception - die dann ja nicht durchlaufen werden - irgendwelche Datenstrukturen hätten initialisieren sollen, das aber nicht erfolgt ist und du später versuchst, darauf zuzugreifen. :idea:
[...]
Weiterhin gilt: Narses hat folgendes geschrieben: | Aber ohne den Code zu kennen, kann ich nicht mehr dazu sagen. :nixweiss: |
|
schippi hat folgendes geschrieben: |
Ich übertrag ja mehrere Frames. Werden beispielsweise 150000 Bytes übertragen, dann ist "size=150000" und die Daten werden halt auf 3 Frames aufgeteilt. Eigentlich sogar 4. Size kommt in einen extra Frame. |
Was machst du denn mit den Daten? Alle im RAM lagern? :gruebel:
cu
Narses
schippi - Di 23.10.07 14:03
Hallo!
Das mit dem Code ist ein bißchen schwierig, weil der Code ziemlich umfangreich ist, es jetzt funktioniert und ich nicht genau weiß woran es genau lag. Aber ich benutze einige male "System.Move()" und das könnte meiner Meinung nach nicht ganz unkritisch sein, falls der reservierte Speicherbereich überschritten wird.
Hier z. B. mal was, das trotz Try-Except eine AccessViolation auslöst.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| Procedure TForm1.Button1Click(Sender: TObject); Var CheckSum: PByte; TestW: Word; SizeCheckSum, TestInt, Zahl: Integer; Begin TestW := 999; TestInt := 100; Zahl := 3; Try SizeCheckSum := 7; GetMem(CheckSum, SizeCheckSum); FillChar(CheckSum^, SizeCheckSum, 0);
System.Move(Pointer(@TestW)^, CheckSum^, 2); inc(CheckSum, 4); System.Move(Pointer(@TestInt)^, CheckSum^, 4); Inc(CheckSum, 4); System.Move(Pointer(@Zahl)^, CheckSum^, 4); Inc(CheckSum, 4); System.Move(Pointer(@Zahl)^, CheckSum^, 4); Inc(CheckSum,19);
Dec(Checksum, SizeCheckSum);
FreeMem(CheckSum, SizeCheckSum); Except showmessage('a'); End; End; |
Beim ersten mal, wenn man den Button1 drückt funktionierts und beim 2. mal nicht mehr. Falls es trotzdem immer funktioniert, einfach mal die Werte bei Inc ein bißchen ändern.
Zitat: |
Was machst du denn mit den Daten? Alle im RAM lagern?
|
Ich bekomme die Daten, kopiere sie in einen String (wo wir wieder bei system.move wären :wink: ), bilde die Checksum und falls die stimmt, übergeb ich den String einer Funktion in einer DLL.
So kopiere ich die Daten in den String:
Delphi-Quelltext
1: 2:
| SetLength(Data, DataLength); System.Move(PChar(PA.Inbound.Strings[5])^, Pointer(@Data[1])^, DataLength); |
Grüße
Narses - Di 23.10.07 14:19
Moin!
:hair:
schippi hat folgendes geschrieben: |
Aber ich benutze einige male "System.Move()" und das könnte meiner Meinung nach nicht ganz unkritisch sein, falls der reservierte Speicherbereich überschritten wird. |
:shock: Wenn du das doch schon weißt, warum gehst du dann nicht entsprechend vorsichtig damit um?! :?
schippi hat folgendes geschrieben: |
Hier z. B. mal was, das trotz Try-Except eine AccessViolation auslöst.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| Procedure TForm1.Button1Click(Sender: TObject); Var CheckSum: PByte; TestW: Word; SizeCheckSum, TestInt, Zahl: Integer; Begin TestW := 999; TestInt := 100; Zahl := 3; Try SizeCheckSum := 7; GetMem(CheckSum, SizeCheckSum); FillChar(CheckSum^, SizeCheckSum, 0);
System.Move(Pointer(@TestW)^, CheckSum^, 2); inc(CheckSum, 4); System.Move(Pointer(@TestInt)^, CheckSum^, 4); Inc(CheckSum, 4); System.Move(Pointer(@Zahl)^, CheckSum^, 4); Inc(CheckSum, 4); System.Move(Pointer(@Zahl)^, CheckSum^, 4); Inc(CheckSum,19);
Dec(Checksum, SizeCheckSum);
FreeMem(CheckSum, SizeCheckSum); Except showmessage('a'); End; End; |
Beim ersten mal, wenn man den Button1 drückt funktionierts und beim 2. mal nicht mehr. Falls es trotzdem immer funktioniert, einfach mal die Werte bei Inc ein bißchen ändern. |
:eyecrazy: Und du wunderst dich tatsächlich, dass das nicht richtig funktioniert?! :roll:
Ich möchte hier sicherheitshalber einmal kurz klarstellen, dass das überhaupt nix mit den TNBFPA-Komponenten zu tun hat, wenn dein Code bei solchen Aktionen abschmiert! :?
cu
Narses
//EDIT: "bei solchen Aktionen" in den letzten Satz eingefügt. ;)
Lossy eX - Di 23.10.07 14:58
Narsens: Also ich würde von meinem Code nie behaupten, dass er vollkommen fehlerfrei ist. Sondern immer, dass er keine offensichtlichen Fehler mehr enthält. Alles Andere kann man nie mit Gewissheit sagen. Nur nahezu ausschließen. ;)
Schippi: Nichts destro trotz teile ich Narsens Meinung. Mich würde mal interessieren was du mit dem Code vor hast? Willst du nur einen Fehler produzieren? Dann wäre der Zugriff auf einen nil pointer die bessere Alternative. Denn das erzeugt genau nur eine Zugriffsverletzung und du zerstörst damit keine fremden Speicherbereiche.
Denn nichts anderes tust du da. Du schreibst willenlos in anderen Speicherbereiche und gibst davon auch noch Stücke frei, denn 4 + 4 + 4 + 19 sind nicht 7. Und damit erreichst du lediglich, dass die Intigrität anderer Programmteile nicht mehr gewährleistet werden kann.
Der Speichermanager von Delphi alloziiert größere Speicherbereiche und bei GetMem wird ein kleineres Stück davon zurückgegeben. Wenn du jetzt eine Zugriffsverletzung bekommst dann besagt die lediglich, dass du außerhalb eines von Delphi kontrollierten Bereiches zugreifen wolltest. Wenn dein Pointer aber genau innerhalb eines solchen Blockes liegt hast du noch einige Kilobytes (keine Ahnung wie viel genau) in denen andere Daten von deinem Programm stecken können. Wenn du Glück hast wird der Block nicht benutzt. Dann passiert rein gar nichts. Aber ansonsten kann so ziemlich alles passieren.
[Edit] Was ich ganz vergessen habe. Dadurch dass du andere Bereiche veränderst schaffst du es natürlich solch einen Try Except Block zu umgehen, da du zwar noch im Speicher von Delphi bist aber die Daten von Programmcode zerstört hast die auf so etwas nicht gefasst sind. Also die nicht in einem Try Except Block liegen. Aus Geschwindigkeitsgründen etc. Das bedeutet der Fehler kommt eigentlich woanders her wird aber vor dir hervorgerufen.
Narses - Di 23.10.07 15:06
Moin!
Lossy eX hat folgendes geschrieben: |
Narsens: Also ich würde von meinem Code nie behaupten, dass er vollkommen fehlerfrei ist. Sondern immer, dass er keine offensichtlichen Fehler mehr enthält. Alles Andere kann man nie mit Gewissheit sagen. Nur nahezu ausschließen. ;) |
:) Hast ja recht, war nur so geschockt. ;) Hiermit ziehe ich also öffentlich die Fehlerfreiheit meines Codes wieder in den bezweifelbaren Bereich. 8)
habe meinen Code nie als grundsätzlich Fehlerfrei hingestellt - hätte man aber vielleicht in meinem letzten Post so lesen können, OK
Lossy eX hat folgendes geschrieben: |
Schippi: Nichts destro trotz teile ich Narsens Meinung. Mich würde mal interessieren was du mit dem Code vor hast? |
Das würde mich allerdings auch interessieren. :gruebel:
cu
Narses
//EDIT: @
Lossy eX: Danke für die Erläuterungen; hätte ich auch mal machen können, statt mich aufzuregen... :oops: Also, "Sorry" an
schippi :beer:
schippi - Di 23.10.07 15:21
Hallo Narses!
Mir ist schon klar, dass man damit vorsichtig umgehen muss und dass das nicht funktioniert..
Hab halt verschiedene Fehlerfälle durchgespielt und da war auch der Fehler mit System.move dabei. Dachte dass sich das trotzdem irgendwie abfangen lässt, wenn so was mal passieren sollte. Weiß halt nicht wie und habs deswegen hier gepostet.
Zitat: |
Ich möchte hier sicherheitshalber einmal kurz klarstellen, dass das überhaupt nix mit den TNBFPA-Komponenten zu tun hat, wenn dein Code abschmiert! |
Ich wollte nicht, dass das so rüberkommt, als wäre deine Komponente daran Schuld.
Ich hab deine Socketkomponente nur angesprochen, weil sich das Try-Except mit Einbinden der Komponente anders verhielt als ohne und ich wusste nicht warum. Da du ja in diesem Forum bist und es wahrscheinlich am besten weißt...
Ich hoffe, ich hab jetzt nochmal die Kurve gekriegt :wink:
Lossy eX - Di 23.10.07 15:36
Narsens: War auch nicht ganz ernst gemeint. ;)
Schippi: Okay. Fehlerfälle durchspielen ist durchaus ein Argument. Allerdings löst dein Code ja nicht direkt den Fehler aus sondern nur indirekt und damit nützt das Try Except in dem Falle gar nichts. Außer du würdest auf ungültigen Speicher zugreifen.
Aber einige Fehlerfälle dürfen auch einfach nicht passieren. Zum Beispiel wenn du an die Adresse deiner lokalen Variable schreibst. Zum Beispiel ein lokales statisches Array. Dann befinden sich diese Daten auf dem Stack und wenn du dort rüber schreibst kann es passieren, dass du dir die Daten des Try Except Blockes zerschießt was dann zur Folge hat dass Delphi nicht mehr weiß was es machen soll. Und schwupp ist deine gesammte Anwendung weg.
Besser ist es sich genau Gedanken zu machen was passieren könnte und darauf so gut wie möglich zu reagieren. Testen kann man leider sowieso nicht alles.
schippi - Di 23.10.07 18:08
Zitat: |
Also, "Sorry" an schippi :beer:
|
Kein Problem! Hab halt auch blöd gefragt, dann bekommt man ja bekanntermaßen auch ne blöde Antwort :wink:
Also wenn jemand noch ein dümmerer Fehler einfällt als mir, dann her damit. Ich bring dann damit mein Programm zum Absturz und frag anschließend Narses, was mit seiner Komponente nicht stimmt :zwinker:
Viele Grüße
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!