Ist das FreePascal BUG?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Ist das FreePascal BUG?

Beitrag von Soner »

Kann es sein dass hier Free Pascal ein Fehler macht oder ich? Das ganze wird in Delphimodus kompiliert.
Ich erkläre es am besten mit Quelltext liest bitte Kommentare.
Die Variable i ist integer, Item.FChildren.Count ist auch integer und es ist manchmal 1 und manchmal 0.

Code: Alles auswählen

 
 for i := 0 to (Item.FChildren.Count - 1) do begin
     // dieser block wird 2 mal ausgeführt  wenn Item.FChildren.Count=1 ist
     // und erzeugt natürlich Index Fehler, weil i ist 1 und
 end;
 


Dann habe ich es variert zu:

Code: Alles auswählen

 
 k:= (Item.FChildren.Count - 1);
 for i := 0 todo begin
     // dieser Block wird auch zwei mal ausgeführt  bei count=1
     // wie bei Variation 1
 end;
 


Dann habe ich es zu While-Schleife geändert und da läuft es richtig:

Code: Alles auswählen

 
 i:= 0;
 while i<Item.FChildren.Count do
     // Jetzt läuft es richtig, d.h.  bei
     // Item.FChildren.Count =1 wird es nur einmal ausgeführt
    Inc(i);
 end;
 


Ich habe dann in einem Neuen Beispielprogramm ähnliches gemacht, da lief es ohne Probleme, auch in Delphimodus:

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
var i, k: integer;
begin
  k:=(1-1);
  for i:=0 to k do
    Caption:=i.ToString;
end;
 

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Ist das FreePascal BUG?

Beitrag von Mathias »

Was ist Item, eine Deklaration wäre hilfreich.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Ist das FreePascal BUG?

Beitrag von Soner »

Item ist TElTreeItem = class(TPersistent).
Ich lade das ganze mal hoch, es ist sowieso Freeware sofern man kein Abkömmling erstellt. Es ist Eltree-lite, ich habe im Schnelldurchgang zu Lazarus convertiert. Es läuft aber zeichnet keine "tree-items", ich muss noch Zeichen routinen überarbeiten.
Nun zurück zum Problem, es geht allgemein um dieses Verhalten, das habe ich bei Freepascal schon einige male mit Listen erlebt.
Diese Schleife befindet sich in ElTree.pas (procedure TElTreeItems.Iterate;).
Wenn ihr Beispielprogramm ladet und es laufen läßt, stoppt der Debugger ein paarmal dort, aber diese Zählen nicht. Erst wenn es erst in Eltreeesimplelaz1form.pas bei der Zeile:

Code: Alles auswählen

    aLand:=ElTree1.Items.AddItem(nil);

stoppt, dann achten, weil es dann anschließend bei

Code: Alles auswählen

procedure TElTreeItems.Iterate;

stoppt und dann ist das Fehlverhalten zu beobachten.

Originale Prozedure ist das hier:

Code: Alles auswählen

 
  procedure IntIterate(VisibleOnly: boolean; Item: TElTreeItem);
  var
    i: integer;
  begin
    inc(j);
    if (j >= 0) and ((not VisibleOnly) or ((not Item.Hidden) or (not FOwner.FilteredVisibility))) then IterateProc(Item, j, DoContinue, IterateData, FOwner);
    if not (DoContinue) then exit;
    if (not (VisibleOnly)) or (Item.Expanded) then
      for i := 0 to Item.FChildren.Count - 1 do
      begin
        if (not VisibleOnly) or ((not TElTreeItem(Item.FChildren[i]).Hidden) or (not FOwner.FilteredVisibility)) then
          IntIterate(VisibleOnly, TElTreeItem(Item.FChildren[i]));
        if not (DoContinue) then exit;
      end;
  end;
 
Dateianhänge
eltreelite-pub.7z
(155.22 KiB) 64-mal heruntergeladen

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Ist das FreePascal BUG?

Beitrag von mschnell »

Soner hat geschrieben:1:
for i := 0 to (Item.FChildren.Count - 1) do begin
...
2:
k:= (Item.FChildren.Count - 1);
for i := 0 to k do begin
...
3:
i:= 0;
while i<Item.FChildren.Count do
...

1: Item.FChildren.Count wird nur einmal vor der Schleife ausgewertet (anders als bei einem "for"-statement in C ).
2: ebenso, hier aber offensichtlich (wäre auch in C so) )
3: Item.FChildren.Count wird bei jedem Schleifendurchgang ausgewertet.

Wenn item in der Scheife verändert wird, kann es zu besagtem Index-Fehler / Zugriffsverletzung kommen.

-Michael

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Ist das FreePascal BUG?

Beitrag von Soner »

mschnell hat geschrieben:...
1: Item.FChildren.Count wird nur einmal vor der Schleife ausgewertet (anders als bei einem "for"-statement in C ).
2: ebenso, hier aber offensichtlich (wäre auch in C so) )
..
-Michael

So sollte es sein, aber das macht es nicht. Ich prüfe sowohl vor Schleifeneintritt auch auch in der Schleife auf Item.FChildren.Count, obwohl es 1ist, läuft die Schleife zweimal.

Code: Alles auswählen

 
      i:=Item.FChildren.Count; // = 1
      for i := 0 to (Item.FChildren.Count - 1) do
            begin
              k:=Item.FChildren.Count; // = 1, auch beim 2. Schleifenlauf
              if (not VisibleOnly) or ((not TElTreeItem(Item.FChildren[i]).Hidden) or (not FOwner.FilteredVisibility)) then
                IntIterate(VisibleOnly, TElTreeItem(Item.FChildren[i]));
              if not (DoContinue) then exit;
            end;   
 

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Ist das FreePascal BUG?

Beitrag von Soner »

Ich habe es ganz oben geschrieben aber mache mal deutlich, ist das nicht falsches Laufverhalten?

Code: Alles auswählen

 
      b:=(Item.FChildren.Count - 1);
     // obwohl b=0 ist wird die schleife fortgesetzt und i wird 1.
      for i := 0 to b do
            begin
              k:=Item.FChildren.Count;
              if (not VisibleOnly) or ((not TElTreeItem(Item.FChildren[i]).Hidden) or (not FOwner.FilteredVisibility)) then
                IntIterate(VisibleOnly, TElTreeItem(Item.FChildren[i])); //hier wird die Prozedur nochmal aufgerufen, Rekursion.
              if not (DoContinue) then exit;
             //hier musste die Schleife Verlassen werde, weil b=0 ist, aber geht weiter zum Schleifenanfang.
            end;
    end;   
 


Ich glaube ich habe den Fehler gefunden. Weil das eine Rekursion ist, kompiliert der freepascal den Kode falsch, anders ist es nicht zu erklären.

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Ist das FreePascal BUG?

Beitrag von Soner »

Ich habe weiter mit Debugger untersucht:

Code: Alles auswählen

 
 
  procedure IntIterate(VisibleOnly: boolean; Item: TElTreeItem);
  var
    i: integer;
  begin
    inc(j);
    if (j >= 0) and ((not VisibleOnly) or ((not Item.Hidden) or (not FOwner.FilteredVisibility))) then
        IterateProc(Item, j, DoContinue, IterateData, FOwner); //<--- hier gibt es auch falsches Verhalten
        //Vor dem Eintritt in IterateProc ist:    item<>nil und DoContinue=true, j=0
        //in die IterateProc-FUnktion kommt an, immer : Item=nil
       // DoContinue= irgend ein integer zahl,
        //j= irgend ein integer zahl,
 
 
    if not (DoContinue) then exit;
    if (not (VisibleOnly)) or (Item.Expanded) then
      for i := 0 to Item.FChildren.Count - 1 do
      begin
        if (not VisibleOnly) or ((not TElTreeItem(Item.FChildren[i]).Hidden) or (not FOwner.FilteredVisibility)) then
          IntIterate(VisibleOnly, TElTreeItem(Item.FChildren[i]));
        if not (DoContinue) then exit;
      end;
  end;
 


Wenn ich mich nicht irre, muß es ein Freepascal-Fehler geben.
.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Ist das FreePascal BUG?

Beitrag von wp_xyz »

Um die FPC-Leute davon zu überzeugen, dass hier wirklich ein Compiler-Fehler vorliegt, musst du ein einfaches Test-Projekt erstellen, das den Fehler zeigt. Eine Fremdkomponente mit 20 Dateien wird sich niemand ansehen.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Ist das FreePascal BUG?

Beitrag von Timm Thaler »

Soner hat geschrieben:Ich glaube ich habe den Fehler gefunden. Weil das eine Rekursion ist, kompiliert der freepascal den Kode falsch, anders ist es nicht zu erklären.


Nanana, vielleicht solltest Du den Fehler mal bei Dir suchen. for ... do ist ja nun keine neue Erfindung, meinst Du nicht, es wäre auch anderen schon aufgefallen, wenn das falsch kompiliert würde.

Leider gibst Du nur unvollständige Angaben, daher ist das nur Vermutung:

for führt nicht die Schleife zweimal aus, sondern for führt die Schleife einmal aus, so wie das sein soll, geht dann in die Rekursion und führt die Schleife nochmal aus. Jedesmal ist i = 0 und nach der Schleife 1.

Den Abbruch nach dem zweiten Ausführen macht dann DoContinue, wobei unklar ist, wo das mit welchen Werten gefüttert wird.

Antworten