Autor |
Beitrag |
Daniel L.
      
Beiträge: 140
Erhaltene Danke: 14
W7, W8
TurboD Prof, Delphi Community
|
Verfasst: Mi 03.09.08 22:57
Hallo, ich stolpere gerade über merwürdiges Compilerverhalten in D7 Peronal::
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| type
Trec1 = record i, k, l : integer; end;
Trec2 = record i, k : integer; end;
procedure unklar; var ar1 : array of Trec1; ar2 : array of Trec2; begin setLength (ar1, 5); ar1 [40].i := 123; ShowMessage (IntToStr (ar1 [40].i)); setLength (ar2, 5); ar2 [40].i := 123; end; |
Die Onlinhilfe verwirrt auch:
Zitat: | "Durch Zuweisungen an ein dynamisches Array über den Index ... wird für das Array kein neuer Speicherplatz reserviert. Der Compiler akzeptiert auch Indizes, die außerhalb des angegebenen Bereichs liegen." |
Bug, oder was kapier ich da nicht?
Danke : Daniel Lutz
Moderiert von Narses: Code- durch Delphi-Tags ersetzt
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 03.09.08 23:05
Der Delphi-Compiler führt bestimmte Prüfungen in einer Art Aufgaben-Stack aus, d.h. zuletzt deklarierte Variablen werden zuerst geprüft. Kommentier mal Ar2 aus und der Compiler sollte über Ar1 meckern.
Was mich aber viel mehr wundert, ist eine andere Geschichte: Warum der RangeCheck (was ja eine Runtime-Überprüfung ist), nicht bereits bei Ar1 anschlägt. Dass zur Compile-Zeit keine Warnung ausgegeben wird, liegt an den dynamischen Arrays, da der Compiler diese nicht auf ihre Länge hin (statisch) prüfen kann (Das wäre die Stack-Basierte Prüfung). Die dynamischen Prüfungen werden Inline ausgeführt (d.h. durch Code, der direkt vor oder nach bestimmten Aktionen eingefügt wird).
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Daniel L. 
      
Beiträge: 140
Erhaltene Danke: 14
W7, W8
TurboD Prof, Delphi Community
|
Verfasst: Mi 03.09.08 23:14
das Auskommentieren ändert nichts, es wird NUR bei ar2 gemeckert, was ich durch Vertauschen der Zuweisungsreihefolge (also erst ar2) feststelle.
krass---
Daniel
--- Moderiert von Narses: Beiträge zusammengefasst---
ich hab noch weitere Tests gemacht:
Der RangeCheck scheint immer bei dyn. arrays, die Records mit GENAU 3 Feldern (also nicht 1, 2 oder 4) aufnehmen, bei Überschreitung des oberen Index keine Fehlermeldung zur Laufzeit zu melden - übrigens ebenso in TurboDelphi.
ganz schön heftig...und wirklich unverständlich, da auf einem Index > High ja tatsächlich ein Wert gespeichert wird und dann auch wieder abrufbar ist!
verwirrt: Daniel
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 04.09.08 23:00
Unter Projekt --> Optionen --> Compiler kannst du rechts oben auch die entsprechende Überprüfung einschalten. Dann wird überprüft ob die Indizes im erlaubten Bereich liegen, und falsche Werte auch bei dynamischen Arrays ggf. per Exception abgefangen.
Allerdings wird das Programm dadurch natürlich langsamer, weshalb man lieber selber dafür sorgen sollte, dass da alles stimmt, um jedoch "unerklärliche" Fehler zu finden ist das eine schnelle Möglichkeit um herauszufinden ob man schlicht irgendwo Speicher durch falsche Indizes überschreibt.
Den eigentlichen Fall hier schaue ich mir auch mal an, ich wollte nur erstmal darauf hinweisen  .
// EDIT:
Ich merke gerade, dass der Fehler sowieso nur ausgegeben wird, wenn die Option aktiviert ist, nur eben bei ersten Mal nicht. Hmm, mal den generierten Assemblercode anschauen...
// EDIT2:
Dass das durch geht ist kein Wunder, es wird gar kein Überprüfungscode generiert vor dem Zugriff, beim zweiten aber schon. Das ist schon seltsam:
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: 31: 32: 33: 34: 35: 36: 37:
| Unit77.pas.39: setLength (ar1, 5); 00457E57 6A05 push $05 00457E59 8D45FC lea eax,[ebp-$04] 00457E5C B901000000 mov ecx,$00000001 00457E61 8B15007E4500 mov edx,[$00457e00] 00457E67 E804D9FAFF call @DynArraySetLength 00457E6C 83C404 add esp,$04 Unit77.pas.40: ar1 [40].i := 123; // geht so durch (!!!!) 00457E6F B828000000 mov eax,$00000028 00457E74 8D0440 lea eax,[eax+eax*2] 00457E77 8B55FC mov edx,[ebp-$04] 00457E7A C704827B000000 mov [edx+eax*4],$0000007b Unit77.pas.41: ShowMessage (IntToStr (ar1 [40].i)); // 123 00457E81 B828000000 mov eax,$00000028 00457E86 8D0440 lea eax,[eax+eax*2] 00457E89 8B55FC mov edx,[ebp-$04] 00457E8C 8B0482 mov eax,[edx+eax*4] 00457E8F 8D55F4 lea edx,[ebp-$0c] 00457E92 E84D07FBFF call IntToStr 00457E97 8B45F4 mov eax,[ebp-$0c] 00457E9A E89D44FDFF call ShowMessage Unit77.pas.42: setLength (ar2, 5); 00457E9F 6A05 push $05 00457EA1 8D45F8 lea eax,[ebp-$08] 00457EA4 B901000000 mov ecx,$00000001 00457EA9 8B15207E4500 mov edx,[$00457e20] 00457EAF E8BCD8FAFF call @DynArraySetLength 00457EB4 83C404 add esp,$04 Unit77.pas.43: ar2 [40].i := 123; // ---> ERangeError (wie erwartet) 00457EB7 B828000000 mov eax,$00000028 00457EBC 8B55F8 mov edx,[ebp-$08] 00457EBF 85D2 test edx,edx 00457EC1 7405 jz $00457ec8 00457EC3 3B42FC cmp eax,[edx-$04] 00457EC6 7205 jb $00457ecd 00457EC8 E863B8FAFF call @BoundErr 00457ECD C704C27B000000 mov [edx+eax*8],$0000007b |
//EDIT3:
Sobald mehr als 2 Elemente in dem Record sind, ist die Bereichsüberprüfung weg (auch im zweiten). O.o
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 05.09.08 01:52
Da hat Borland dann also offensichtlich geschlampt!!!
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 05.09.08 02:04
Richtig und wie ich gerade feststelle haben sie das auch gemerkt, denn in Delphi 2007 ist der Bug nicht mehr vorhanden.
|
|
Daniel L. 
      
Beiträge: 140
Erhaltene Danke: 14
W7, W8
TurboD Prof, Delphi Community
|
Verfasst: Fr 05.09.08 11:00
tja, hatte mich ganz schön Zeit gekostet, diesen Bug zu finden, ich hatte mich natürlich auf die Bereichsprüfung verlassen und mich nicht sooo sehr um meine Indizes gekümmert, sondern den Fehler in meiner Anwendung woanders gesucht.
g: Daniel
|
|
|