Autor Beitrag
Daniel L.
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Mi 03.09.08 22:57 
Hallo, ich stolpere gerade über merwürdiges Compilerverhalten in D7 Peronal::
ausblenden 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;                   //   geht so durch  (!!!!)
  ShowMessage (IntToStr (ar1 [40].i));   //   123

  setLength (ar2, 5);
  ar2 [40].i  := 123;                     // ---> ERangeError (wie erwartet)
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 user profile iconNarses: Code- durch Delphi-Tags ersetzt
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: 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 user profile iconNarses: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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:
ausblenden volle Höhe 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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: 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