Unit SysUtils erzeugt Speicherleck unter Linux

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Mathias
Beiträge: 6713
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Mathias »

Ich habe folgendes Test Programm.

Code: Alles auswählen

program Project1;
uses
  SysUtils, heaptrc;
begin
  WriteLn('Ende');
end.       
Dabei habe ich folgende Ausgabe:

Linux:

Code: Alles auswählen

$ ./project1
Ende
An unhandled exception occurred at $000000000046C176:
EAccessViolation: Access violation
  $000000000046C176

Heap dump by heaptrc unit of "/home/tux/fpcupdeluxe_trunk/projects/project1"
16 memory blocks allocated : 3518/3544
14 memory blocks freed     : 3446/3472
2 unfreed memory blocks : 72
True heap size : 524288 (1568 used in System startup)
True free heap : 522208
Should be : 522264
Call trace for block $000076C191C0C200 size 40
  $00000000004149C0
Call trace for block $000076C191C0C100 size 32
Bei Windows scheint es io. zu sein, wobei es beim Heap auch eine Abweichung gibt.

Windows mit wine:

Code: Alles auswählen

$ wine project1.exe 
Ende
Heap dump by heaptrc unit of "Z:\home\tux\fpcupdeluxe_trunk\projects\project1.exe"
0 memory blocks allocated : 0/0
0 memory blocks freed     : 0/0
0 unfreed memory blocks : 0
True heap size : 196608 (2432 used in System startup)
True free heap : 194176
Ist dies ein Bug ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von wp_xyz »

Bin gerade auf Linux und kann das nicht reproduzieren. Was passiert, wenn du die Unit heaptrc aus der Uses-Zeile entfernst und stattdessen das Häkchen für HeapTrc in den Projekt-Optionen setzt? Denn eigentlich soll man heaptrc nicht manuell in der Uses-Zeile aufführen (https://wiki.freepascal.org/heaptrc#Why ... e_manually)-

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

Heaptrc registriert einen Memory Manager. Das muss immer als aller erstes passieren. Du includest aber SysUtils zu erst bevor du HeapTrc nutzt. SysUtils macht ne ganze menge Zeugs wenn die Unit geladen wird, u.a. werden die Exception Objekte für Out of Memory erzeugt (denn wenn die Exception auftritt und der Speicher voll ist kann man keinen neuen Speicher für das Exception Objekt alloziieren).

Das Problem ist also, SysUtils erzeugt neue Speicherobjekte mit dem Standard Memory Manager, danach wechselst du den Memory Manager zu Heaptrc. Das führt natürlich zu Problemen und warum du diese Access Violation bekommst.

Tausch die Position von Heaptrc und SysUtils in der Uses Klausel und es sollte funktionieren.

PascalDragon
Beiträge: 904
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von PascalDragon »

Warf hat geschrieben: Mo 18. Nov 2024, 20:11 Tausch die Position von Heaptrc und SysUtils in der Uses Klausel und es sollte funktionieren.
Besser, wie wp_xyz gesagt hat, die -gh-Option nutzen, statt die Unit manuell einzubinden.
FPC Compiler Entwickler

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Mathias »

Heaptrc registriert einen Memory Manager. Das muss immer als aller erstes passieren.
Danke, dies war es. Habe wohl vor lauter Bäume den Wald nicht gesehen.
Besser, wie wp_xyz gesagt hat, die -gh-Option nutzen, statt die Unit manuell einzubinden.
Was ist daran besser ?

Nur leider scheint es nicht zu funktionieren, wen etwas über eine C lib läuft.

Da erzeuge einen Leak, aber mit heaptrc scheint alles io. zu sein. Egal ob im uses-Klausel oder mit "-gh".

Code: Alles auswählen

uses
  heaptrc, glib2;
var
  p: gpointer;
begin
  p := g_malloc(100);
end.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von af0815 »

Mathias hat geschrieben: Di 19. Nov 2024, 08:42 Da erzeuge einen Leak, aber mit heaptrc scheint alles io. zu sein. Egal ob im uses-Klausel oder mit "-gh".

Code: Alles auswählen

uses
  heaptrc, glib2;
var
  p: gpointer;
begin
  p := g_malloc(100);
end.
Ganz einfach, das geht komplett am heaptrace vorbei, weil es ja nur überwachen kann, was über seinen Memorymanager angefordert wird. Du forderst aber über den Memorymanager von SDL an, daher weis heaptrace nichts davon und alles ist gut.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

Heaptrc ist zwar ein recht einfacher weg Speicherlecks zu entdecken aber recht limitiert. Es kann nur speicherlecks entdecken die über heaptrc alloziiert wurden und das auch nur aus Pascal code heraus. Was deutlich mehr Funktionen bereitstellt ist Valgrind.

Kommt aber mit seinen eigenen Problemen (Linux spezifisch, langsame emulation, etc.)

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Mathias »

Heaptrc ist zwar ein recht einfacher weg Speicherlecks zu entdecken aber recht limitiert.
So wie ich das verstehe, ist dies sehr tief in Pascal verankert so wie der Debugger, Bereich und Überlauf-Prüfung ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

In etwa. Valgrind ist ein kompletter emulator. Der jede einzelne Instruktion betrachtet und schaut ob die irgendwelche sachen macht die sie nicht soll.
Damit ist es extrem mächtig, aber programme in Valgrind emulieren zu lassen bedeutet auch das sie um etwa einen Faktor 1000 langsamer laufen. Daher für größere Projekte nicht unbedingt anwendbar, und man muss seine Funktionaltität in Unittests aufteilen und die dann mit Valgrind testen

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

Übrigens was auch ein super trick mit Heaptrc ist was viele vergessen, heaptrc.KeepReleased:

Code: Alles auswählen

uses
  HeapTrc, Classes;

procedure UseAfterFree;
var
  sl1, sl2: TStringList;
begin
  HeapTrc.KeepReleased := True;
  sl1 := TStringList.Create;
  sl1.Add('Hello SL1');
  sl1.Free;

  sl2 := TStringList.Create;
  sl2.Add('Hello SL2');
  WriteLn(sl1.Text); // Use of sl1 after it has been freed above
  sl2.Free;
end;
Wenn man die erste Zeile "HeapTrc.KeepReleased := True;" streicht läuft das oben ohne Fehler durch und man erhalt ein "falsches" ergebnis, mit der Zeile crashts und man sieht direkt den Use-after-free bug

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von af0815 »

Warf hat geschrieben: Di 19. Nov 2024, 14:49 Übrigens was auch ein super trick mit Heaptrc ist was viele vergessen, heaptrc.KeepReleased:
Danke für die Info, gibt es vielleicht noch mehr so "unbekannte Spezialitäten" ?

Ich verwende in meinen *.lpr gerne folgendes

Code: Alles auswählen

uses ....,sysutils,...
......
{$if declared(UseHeapTrace)}
const
  co_heaptrc = 'heaptrace.trc';
{$endif}
var
  ErrorMsg : String;
begin
// If you want to show heaptrc report dialog only if there were leaks
//   in your application, then put this command somewhere
//   in your main project source file:
{$if declared(UseHeapTrace)}
  GlobalSkipIfNoLeaks := true; // supported as of debugger version 3.1.1
  if FileExists(co_heaptrc) then
      DeleteFile(co_heaptrc);
  SetHeapTraceOutput(co_heaptrc); // supported as of debugger version 3.1.1
  //   HaltOnError := false;             // dont halt a the end of the programm
{$endif}
.....
end;
Damit muss ich mich nicht mit dem Heaptrace Fenster herumschlagen und bekomme das ganze einfach sauber in einer Datei serviert zum gemütlichen Analysieren.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Mathias »

Hat schon mal einer valgrind ausprobiert ?$
Ich habe folgendes Programm ausprobiert:

Code: Alles auswählen

var
  p:Pointer;
begin
  Getmem(p, 100);
  WriteLn(PtrUInt(p));
end.  

Code: Alles auswählen

$ valgrind --leak-check=full ./project1 
==6963== Memcheck, a memory error detector
==6963== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==6963== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==6963== Command: ./project1
==6963== 
75497536
==6963== 
==6963== HEAP SUMMARY:
==6963==     in use at exit: 0 bytes in 0 blocks
==6963==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6963== 
==6963== All heap blocks were freed -- no leaks are possible
==6963== 
==6963== For lists of detected and suppressed errors, rerun with: -s
==6963== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Ich muss mal probieren, wie es mit C-Programmen aussieht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

Hast du mit valgrind support kompiliert (Projektoptionen->Debugging->-vg switch)?

Beispiel:

Code: Alles auswählen

➜  cat test.pas
var
  p: Pointer;
begin
  p:=GetMem(1024);
  WriteLn(IntPtr(p));
end.
➜  fpc -g -gv ./test.pas
Free Pascal Compiler version 3.2.2 [2024/05/21] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling ./test.pas
Linking test
6 lines compiled, 0.1 sec
➜  valgrind ./test      
==4692== Memcheck, a memory error detector
==4692== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==4692== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==4692== Command: ./test
==4692== 
78188616
==4692== 
==4692== HEAP SUMMARY:
==4692==     in use at exit: 1,032 bytes in 1 blocks
==4692==   total heap usage: 1 allocs, 0 frees, 1,032 bytes allocated
==4692== 
==4692== LEAK SUMMARY:
==4692==    definitely lost: 0 bytes in 0 blocks
==4692==    indirectly lost: 0 bytes in 0 blocks
==4692==      possibly lost: 0 bytes in 0 blocks
==4692==    still reachable: 1,032 bytes in 1 blocks
==4692==                       of which reachable via heuristic:
==4692==                         length64           : 1,032 bytes in 1 blocks
==4692==         suppressed: 0 bytes in 0 blocks
==4692== Rerun with --leak-check=full to see details of leaked memory
==4692== 
==4692== For lists of detected and suppressed errors, rerun with: -s
==4692== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Das Speicherleck wird als "still reachable" kategorisiert weil p ein globale Variable ist, die bis zum ende der Programmlaufzeit gültig ist. Wenn ichs in ne Lokale Variable verschiebe:

Code: Alles auswählen

procedure Test;
var
  p: Pointer;
begin
  p:=GetMem(1024);
  WriteLn(IntPtr(p));
end;

begin
  Test;
end.
Bekomm ich:

Code: Alles auswählen

==5367== Memcheck, a memory error detector
==5367== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==5367== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==5367== Command: ./test
==5367== 
78188616
==5367== 
==5367== HEAP SUMMARY:
==5367==     in use at exit: 1,032 bytes in 1 blocks
==5367==   total heap usage: 1 allocs, 0 frees, 1,032 bytes allocated
==5367== 
==5367== LEAK SUMMARY:
==5367==    definitely lost: 1,032 bytes in 1 blocks
==5367==    indirectly lost: 0 bytes in 0 blocks
==5367==      possibly lost: 0 bytes in 0 blocks
==5367==    still reachable: 0 bytes in 0 blocks
==5367==         suppressed: 0 bytes in 0 blocks
==5367== Rerun with --leak-check=full to see details of leaked memory
==5367== 
==5367== For lists of detected and suppressed errors, rerun with: -s
==5367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Jetzt ists definitely lost

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

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Mathias »

Hast du mit valgrind support kompiliert (Projektoptionen->Debugging->-vg switch)?
Habe ich noch nicht, dafür bin ich anderswo weiter gekommen.

Mit folgendem Testprogramm, alles Debugzeugs deaktiviert..

Code: Alles auswählen

program project1;
uses
  heaptrc,
  glib2;

  procedure Test;
  var
    p: Pointer;
  begin
    p:=GetMem(1024);
    WriteLn(IntPtr(p));
    Freemem(p);

    p:=g_malloc0(100);
    WriteLn(IntPtr(p));
    g_free(p);
  end;

  begin
    Test;
  end.
Lasse ich Freemem weg, reagiert heaptrc. Lasse ich g_free weg, reagiert valgrind.

Somit kann man valgrind nutzen, wen man Speicher über C-lib Funktionen reserviert und frei gibt. Es reagiert auch, wen man mit gobject Fehler macht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2081
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit SysUtils erzeugt Speicherleck unter Linux

Beitrag von Warf »

Genau, valgrind emuliert das Programm und hängt sich an verschiedenen funktionen rein. Wenn du mit -vg kompilierst, sorgt der FPC dafür das valgrind freundliche funktionen wie malloc oder free verwendet werden für den memory manager.

Ohne das weiß valgrind nicht wann speicher alloziiert wird. Theoretisch wäre es auch möglich MemCheck zu forken und einen Pascal MemCheck zu bauen der GetMem und FreeMem hooked, aber da ist es einfacher einfach den FPC die richtigen funktionen im hintergrund benutzen zu lassen.

Antworten