TsWorksheetGrid: SIGSEGV im AVL-Tree

Rund um die LCL und andere Komponenten
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Ich habe mit dem TsWorksheetgrid ein Problem immer im AVL-Tree, der für die Verwaltung der Zellen verwendet wird. Für mich sieht es so aus, als würde der oberste Parent nicht sauber nil sein.

In einem Frame, in einem Pagecontrol, davon in einem TabSheet ist Clientbedeckend ein TsWorksheetgrid enhalten. In diesem werden zuerst die alten Daten mit Clear gelöscht und die neuen Daten eingetragen. Anschliessend sollte nur die Column Breite angepasst werden.

Mir es aufgefallen, das es viel früher schon Probleme geben kann wenn man in den Projektoptionen Trash Variables aktiviert hat. Leider ist das ganze ein Closed Source Projekt mit Frames in Frames. Somit kann ich es nicht auf ein ganz simples Beispiel herunterbrechen. Hier sind alle Checks in den Projektoptionen aktiviert, Heaptrace ist ein und Trash Variables. Zusätzlich wird für den Debugger -dqrf with sets - mit internen Symbolen gearbeitet.
#0 TAVLTREENODE__SUCCESSOR(0x15d16378) at laz_avl_tree.pp:1410
#1 TSROWCOLENUMERATOR__MOVENEXT(0x15cf66b8) at .\source\common\fpsclasses.pas:547
#2 TSCUSTOMWORKSHEETGRID__AUTOADJUSTCOLUMN(0, 0x138a5e80) at .\source\visual\fpspreadsheetgrid.pas:1422
#3 TSCUSTOMWORKSHEETGRID__AUTOCOLWIDTH(0, 0x138a5e80) at .\source\visual\fpspreadsheetgrid.pas:1381
#4 TFRAMEABLXLS__CB_CHANGE(0x0, 0x1389cf00) at .\framesI20H\frablxls.pas:287
Source in TAvlTree:

Code: Alles auswählen

function TAVLTreeNode.Successor: TAVLTreeNode;
begin
  Result:=Right;
  if Result<>nil then begin
    while (Result.Left<>nil) do Result:=Result.Left;
  end else begin
    Result:=Self;
    while (Result.Parent<>nil) and (Result.Parent.Right=Result) do
      Result:=Result.Parent;  // <----- Result.parent $40ba4444 
    Result:=Result.Parent;
  end;
end;
Wobei Result.parent immer $40ba4444 im Fehlerfall ist. Das kenne ich von den Magic Numbers her, solche Nummern sind oft als Kennzeichen vergeben. Für mich sieht das hier so aus, als würde er nach oben traversieren bis es knallt. Ich habe aber auch nicht gefunden, wo der AVL-Tree initialisiert wird und der Parent auf nil gesetzt wird, weil das sollte ja irgendwo passieren.

Die originalen Sourcen aus frablxls.pas sind

Code: Alles auswählen

  // Write all cells to the worksheet
  Inc(j);
  Query_AU_PrHeiz.First;
  while not Query_AU_PrHeiz.EOF do
  begin
    for i := 0 to Query_AU_PrHeiz.Fields.Count - 1 do  // Skip last Col
      case Query_AU_PrHeiz.Fields[i].DataType of
        TFieldType.ftFloat: begin
          sWorkbookSource1.Worksheet.WriteCellValueAsString(j, i, formatFloat('#,##0.0', Query_AU_PrHeiz.Fields[i].AsFloat),MyFormat);
        end
      else begin
          if SameStr(LeftStr(Query_AU_PrHeiz.Fields[i].FieldName,2),'MP') then begin
            hstr:= Query_AU_PrHeiz.Fields[i].AsString;
            hstr:= StrToDreiKommaStr(hstr,'');
            sWorkbookSource1.Worksheet.WriteCellValueAsString(j, i, hstr ,MyFormat);
          end
          else begin
            sWorkbookSource1.Worksheet.WriteCellValueAsString(j, i, Query_AU_PrHeiz.Fields[i].AsString ,MyFormat);
          end;
        end;
      end;
    Query_AU_PrHeiz.Next;
    Inc(j);
  end;
  for i := 0 to Query_AU_PrHeiz.Fields.Count - 1 do begin   // Skip last Col
    {$IfNDef BuildDebug}
    { TODO -oAndi : Warum geht AutoColWidth nicht ? }
    sWorksheetGrid1.AutoColWidth(i);   // <--- hier wird die SIGSEGV exception geworfen 
    {$EndIf}
  end;
Das ganze ist schon seit mindesten einen Jahr, nur langsam wird es lästig :-)

Any hint wo da was schieflaufen könnte ?!
Zuletzt geändert von af0815 am Mo 22. Mär 2021, 15:27, insgesamt 1-mal geändert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid:

Beitrag von af0815 »

War schon mal aktiv - siehe viewtopic.php?t=11869

Edit:
wenn ich das mit

Code: Alles auswählen

    // Hard set to nil - af
    if longint(Result.Parent) = $40ba4444 then
      Result.Parent:= nil;
absichere, so ist das Problem weg. Einmal in TAVLTreeNode.Successor und einmal in TAVLTreeNode.Prodcessor. Das sind so ziemlich die einigen Stellen, wo Richtung Parent traversiert wird.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

Ich weiß nicht, die obersten Einträge in StackTrace sind meistens Folgefehler von etwas was weiter unten passiert ist, und ich kann mir auch nicht vorstellen, das der AVLTree, der an vielen Stellen in der IDE verwendet wird, einen so zentralen Fehler haben könnte.

Ich tippe eher auf TsWorksheetGrid.AutoAdjustColumn oder das aufrufende TsWorksheetGrid.AutoColWidth. Was mir da im Zusammenhang mit Frames einfällt: Sind wir sicher, dass das Grid hier ein gültiges Handle hat?

Was ist übrigens deine FPSpreadsheet-Version? Denn die Zeilennummern in deinem Stack-Trace weisen bei mir auf ganz andere Routinen.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Es hat nur mit der Traversierung nach oben in TAVLTreeNode.Successor und TAVLTreeNode.Prodcessor zu tun. Die Stelle wo es Auftritt kann unterschiedlich sein.

Es kann auch in einem WriteCellValueAsString auftreten, weil auch dort nach vorhanden sein von Zellen gesucht wird. Beim Debuggen ist mir aufgefallen, das der Parent falsch sein muß. Die Lazarusversion spielt nicht so ganz die Rolle, da ich das Problem seit 2 Jahren versuche zu erschlagen. Weder der 'Wert' hat sich geändert, noch das Verhalten. Auch sind da mehrere FPC und Lazarusversion darüber gelaufen. Es war bisher besonders dann provozierbar, wenn man Trash Variables und den Heaptrace aktiviert hat. Aktuell habe ich es laufend und stabil.

Was mir aufgefallen ist bei dem ganzen Konstrukt im AVL-Tree ist, es wird bei den weiter oben liegenden Routinen im AVL-Tree immer auch der Rootknoten in die Abfrage einbezogen. Nur beim AVLTreeNode kann hier keine Abfrage über den Rootknoten erfolgen, weil dieser erst in höheren Ebenen bekannt ist. Hier wird alleine auf das nil gesetzt und das stimmt hier definitiv nicht. Man kann sich das im Debugger schön ansehen, wie in Richtung Eltern traversiert wird, bis es zu der ungültigen Stelle kommt. Leider kann ich an dieser Stelle nicht auf die wirklichen Zellen casten um so die Logik zu ergründen.

Meiner Meinung nach muss man an der ganz anderen Seite mal suchen. Weil genaugenommen sind es ja Pointer auf die Cells die im AVL-Tree gespeichert werden. Soweit ich das überblicke. Ich habe nur die Logik noch nicht durschaut wie die Cells im AVL-Tree gespeichert werden, da es ja Reihen und Spalten gibt. Wenn ich da die Logik verstehe, kann ich dort auch debuggen. Ich gehe aktuell davon aus, das die Parent-Information aus irgendeinen Grund unter bestimmten Bedingungen verloren geht.

Gibt es wo Doku wie der interen Aufbau des ganzen Konstruktes ist, das in den AVL-Trees gespeichert wird?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

In den Nodes des Cells-AVLTrees sind die TCell-Records gespeichert; diese enthalten den Zeilen- und Spalten-Index.

Code: Alles auswählen

type
  TCell = record
    { Location of the cell }
    Row: Cardinal; 
    Col: Cardinal; 
      ....
Der Baum sortiert die Records nach dem Zeilenindex und für denselben Zeilenindex nach dem Spaltenindex. Es stehen also nur solche Zellen im Worksheet, die wirklich existieren.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Also nur ein einziger Baum und kein Baum im Baum. :D

Nachdem ich nur wenige Zellen habe, wird sich das genauer Debuggen lassen. Mal morgen das vertiefen.

Danke für die Infos.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

af0815 hat geschrieben:
Mo 22. Mär 2021, 19:57
Also nur ein einziger Baum und kein Baum im Baum. :D
Naja, weiß nicht, wie du das meinst. Bei jedem Node kann natürlich wieder ein Teilbaum beginnen. Und neben den Cells gibt es im Worksheet noch mehrere dieser Bäume (für die Formeln, die Hyperlinks usw), die aber nach demselben Prinzip aufgebaut sind.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

wp_xyz hat geschrieben:
Mo 22. Mär 2021, 21:59
Und neben den Cells gibt es im Worksheet noch mehrere dieser Bäume (für die Formeln, die Hyperlinks usw), die aber nach demselben Prinzip aufgebaut sind.
Ok, ich verwende in diesem Workbook keine Formeln, Hyperlinks etc. Es ist genaugenommen ein ganz simples DB Grid, das nur ein paar Strings in die Zellen schreibt.
Das Problem habe ich eingrenzen können auf WriteBackgroundColor und AutoColWidth.

Aktuell suche ich bei TsCells wie das AddCell funktioniert. Ich finde Stelle nicht, wo die Zelle in den AVL-Tree eingehängt wird und der Parent richtig gesetzt wird.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

AddCell führt über ein paar Zwischenstufen zu

Code: Alles auswählen

procedure TAVLTree.Add(ANode: TAVLTreeNode);
// add a node. If there are already nodes with the same value it will be
// inserted rightmost
var InsertPos: TAVLTreeNode;
  InsertComp: integer;
begin
  ANode.Left:=nil;
  ANode.Right:=nil;
  inc(FCount);
  if Root<>nil then begin
    InsertPos:=FindInsertPos(ANode.Data);
    InsertComp:=Compare(ANode.Data,InsertPos.Data);
    ANode.Parent:=InsertPos;
    if InsertComp<0 then begin
      // insert to the left
      InsertPos.Left:=ANode;
    end else begin
      // insert to the right
      InsertPos.Right:=ANode;
    end;
    NodeAdded(ANode);
    BalanceAfterInsert(ANode);
  end else begin
    fRoot:=ANode;
    ANode.Parent:=nil;
    NodeAdded(ANode);
  end;
end; 

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

Hab' gerade für ccr-trunk eine Änderung im TsWorksheetGrid hochgeladen, die einen Crash im beigefügten Programm behebt (Grid in einem Frame, und Zellen werden sehr früh mit Werten versehen). Wahrscheinlich nicht dein Problem, aber trotzdem...
Dateianhänge
crashing_frame.zip
(2.52 KiB) 11-mal heruntergeladen

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Nächste Erkennnis:
in der Funktion TsRowColEnumerator.AutoAdjustColoums kann ich das schon nachweisen. Dort wird mittels eines Enumerator durch die Zellen iteriert. Dort sehe ich bereits das es einen AVL-Tree Node mit Parent=$40ba4444 gibt und das Data ein gültiger Zeiger ist und die Row und Col Info Row=10 und Col=1 ergibt. Ich habe eine Überschriftsreihe und 9 Datenreihen, also insgesamt 10 Reihen (bei ca. 40 Columnen).
Korrigiere ich hier den Parent auf nil, so funktioniert alles ohne Probleme.

Ich verwende Clear, WriteText, WriteBackgroundcolor, WriteCellValueAsString und AutoColWith.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

af0815 hat geschrieben:
Di 23. Mär 2021, 17:54
in der Funktion TsRowColEnumerator.AutoAdjustColoums kann ich das schon nachweisen.
Das klingt schon wahrscheinlicher, denn das ist Code von mir...

Aber wenn du dein Testprojekt für dich behältst, kann ich nicht mitsuchen.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Es ist closed source noch dazu ein gewachsenes und ich kann es in der Konstellation nur hier beobachten. Wenn ich das Frame in eine Testumgebung herauslöse, so bekomme ich den Fehler nicht. Aktuell ist er aber verdammt stabil vorhanden, das ist ein Vorteil. Und mit meinem Workaround kann ich leben. Damit habe ich Zeit um den Fehler einzugrenzen.

Im Bereich des Erzeugen der Knoten ist alles unverdächtig und ich habe kein Problem mit dem Parent. Das habe ich mal feststellen können. Was ich auch weis, wenn die eine Zelle korrigiert ist, so ist ruhe. Auch nach einem clear des Worksheet und dem Neuaufbau gibt es den Fehler nicht. Dann kann man löschen und einfügen was man will. Ich muss die App neu starten um den Fehler wieder zu produzieren.

Kann ich den celltree irgendwie zwischendurch mal debuggen ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von wp_xyz »

af0815 hat geschrieben:
Di 23. Mär 2021, 21:24
Es ist closed source noch dazu ein gewachsenes und ich kann es in der Konstellation nur hier beobachten.
OK, soll mir recht sein. Dann kann ich mich bequem zurücklegen und dich die Arbeit machen lassen.
af0815 hat geschrieben:
Di 23. Mär 2021, 21:24
Kann ich den celltree irgendwie zwischendurch mal debuggen ?
Der AVL-Code gehört zu Lazarus, und da kannst du alles debuggen, wenn du zu "Additions and overrides" gehst, auf "Stored in session" klickst, dann "Add" > "Custom Option" und in der erschienenen "Custom"-Zeile den Eintrag "-gw2" (ohne Anführungszeichen) machst. Damit wird dein Programm mit Debuginformationen auch für die Nicht-Projekt-Units übersetzt (dauert beim ersten mal etwas länger). Nun kommst du mit F7 in alle Units rein (außer RTL und FCL). Evtl musst du auch je nach Umgebung statt -gw2 andere Debug-Informationen auswählen (wie "Debugging" > "Type of debug info").

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4591
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: TsWorksheetGrid: SIGSEGV im AVL-Tree

Beitrag von af0815 »

Leider ist es so, wenn ich den vereinfacht isoliere bzw. extrahiere ist das Problem weg. Es muss was ganz einfaches sein, denn das Problem hat schon etliche Updates überlebt. Es ist das erste mal bei Lazraus 2.x im Jahre 2018 aufgetaucht - siehe Link auf die alten Beiträge weiter oben. Bei den vorherigen Versionen habe ich es damals nicht beobachtet.
wp_xyz hat geschrieben:
Mi 24. Mär 2021, 00:26
.... Damit wird dein Programm mit Debuginformationen auch für die Nicht-Projekt-Units übersetzt ...
Das meinte ich nicht, debuggen kann ich den AVL-Tree und das Worksheet ohne Probleme - notfalls Lazarus selbst.

Ich meinte ob es eine einfache Lösung gibt die ganzen Zellen mit internen Informationen auszugeben. Ich habe dazu nur im AVL-Tree eine Konsistenzprüfung gefunden, nichts aber auf Zellenebene. Ich wollte mir ganz einfach nach jeder Operation die ich im Worksheet mache, den ganzen Baum durchsuchen lassen nach dem falschen/komischen Parent.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten