Abweichung von Freepascal zu Delphi bei Interfaces

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
Antworten
Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von Michl »

Servus,

folgender kleiner Test läuft bei Delphi problemlos durch, bei Freepascal gibt es einen SIGSEGV. Wenn man vorher die Interface-Variable auf nil setzt, funktioniert dies auch bei Freepascal. Welches Verhalten ist das richtigere? Ich sehe Argumente für beide Features:

Code: Alles auswählen

program Project1;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
  SysUtils, Classes;
 
type
  ITestInterface = interface
    ['{DC209DB2-6E2D-4680-93D6-5D9B3983C0D3}']
    function OnlyDummy: integer;
  end;
 
  TFoo = class
  public
    Intf: ITestInterface;
  end;
 
  { TBar }
 
  TBar = class(TComponent, ITestInterface)
  public
    function OnlyDummy: integer;
  end;
 
{ TBar }
 
function TBar.OnlyDummy: integer;
begin
  Result := -1;
end;
 
var
  Foo: TFoo;
  Bar: TBar;
 
begin
//  ReportMemoryLeaksOnShutdown := true;
  Foo := TFoo.Create;
  Bar := TBar.Create(nil);
  Foo.Intf := Bar;
//  Foo.Intf := nil;
  Bar.Free;
  Foo.Free;
end.

PS.: Kann mir jemand erklären, warum man die interfaced Klasse extra aufräumen muss? Dies ist bei Delphi und Freepascal gleich. Leite ich nicht von TComponent (welches andere Interfaces implementiert) ab, funktioniert die Referenzzählung und man braucht "Bar" nicht selber frei zu geben.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von theo »

Ich kann den Fehler nicht reproduzieren.

Lazarus 1.9.0 r56988M FPC 3.0.2 x86_64-linux-gtk2

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von Michl »

Oh, ich habe vergessen zu erwähnen, daß Heaptrc aktiviert sein muss.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von Socke »

Die Exception ist korrekt.

In Foo.Intf hast du noch eine Referenz auf das Objekt Bar gespeichert.
Im Dekonstruktor werden alle verwalteten Typen (insbesondere Strings und Interfaces) aufgeräumt. Für COM-Interfaces wird die Methode _Release aufgerufen.
Zeigt Foo.Intf auf einen ungültigen Speicherbereich, tritt die SIGSEGV auf.
Die Unit heaptrc kann solche fehler durchaus häufiger auftreten lassen, auch wenn sie selbst nicht die Ursache ist.

Wird vor dem Freigeben von Bar, die Variable Foo.Intf auf nil gesetzt, wird bereits dann die Methode _Release aufgerufen.
Hier wird der Aufruf aber problemlos ausgeführt, da das Objekt noch existiert.

In Delphi könnte hier auch eine Exception auftreten, ob dies der Fall ist, hängt aber davon ab, ob der Speicherbereich, in dem Bar gespeichert ist, bereits an das Betriebssytem zurückgegeben wurde.
Falls der Speicherbereich dem Programm noch zugewiesen ist, könnte auch vollkommen ungewollter Code ausgeführt werden.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von mse »


Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von theo »

Was ich nicht ganz verstehe ist, warum ich so ein MemLeak produziere (keine Zugriffsverletzung).

Code: Alles auswählen

  Foo := TFoo.Create;
  Foo.Intf := TBar.Create(nil);
  Foo.Free;   


EDIT: So wird der Speicher korrekt freigegeben.

Code: Alles auswählen

 
  { TBar }
 
  TBar = class(TInterfacedObject, ITestInterface)
  public
    function OnlyDummy: integer;
  end;   

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abweichung von Freepascal zu Delphi bei Interfaces

Beitrag von Socke »

TComponent leitet die Aufrufe von _AddRef und _Release an ein VCLComObject weiter; das wird vermutlich nur für COM-Controls verwendet.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten