Search code examples
lazarus

Why do I get a Wrong signature with HeapTrc?


I simplified the following code at the maximum to only show my problem. When the destructor TClass3.Destroy is done, the action FreeAndNil(FClass3) causes a problem and the program stops. If have a look in the Heap.trc file I can read

Marked memory at $0000000001528FD0 invalid
Wrong signature $2951FD2D instead of 5C063D8B

program Project_testFree;
{$mode objfpc}{$H+}

uses
  sysutils;

type
  TClass1 = class
  private
  protected
  public
    constructor Create;
  end;

  TClass2 = class(TClass1)
  private
  protected
    FTClass2   : cardinal;
  public
  end;

  TClass3 = class
  private
  protected
    FClass3       : TClass1;
  public
    constructor Create;virtual;
    destructor Destroy;override;
  end;

  TClass4 = class(TClass3)
  private
    function GetLocalClass2: TClass2;
  protected
  public
    constructor Create;override;
    destructor destroy;override;
    property pClass2:TClass2 read GetLocalClass2;
  end;

constructor TClass1.Create;
begin
  inherited;
end;

constructor TClass3.Create;
begin
  FClass3               := TClass1.create;
end;

destructor TClass3.Destroy;
begin
  FreeAndNil(FClass3);
  writeln('Destroy');
  inherited Destroy;
end;

constructor TClass4.Create;
begin
  inherited Create;
  pClass2.FTClass2 := 1;
end;

destructor TClass4.destroy;
begin
  inherited destroy;
end;

function TClass4.GetLocalClass2: TClass2;
begin
  result := TClass2(FClass3);
end;

var
  c:TClass4;
begin
  if FileExists('heap.trc') then
   DeleteFile('heap.trc');
  SetHeapTraceOutput('heap.trc');

  c:=TClass4.Create;
  c.free;
end. 

I use Lazarus 1.6.2. Thanks for your help.


Solution

  • You cast FClass3 to be TClass2. But you instantiated TClass1. The cast is therefore incorrect which would explain the error. Essentially, you lied to the compiler and it exacted its revenge.

    Had you used a checked cast, using as, then a runtime error would have been raised.