[fpc-devel] Interfaced Object leak in inherited Object

alphax acmui_2004 at 163.com
Mon Jun 13 09:31:53 CEST 2005


It seems a bug in FPC 2.0.0.(Delphi 7.1 also has this bug)

Assumes there is an object(not class) declaration, the object has a IInterface field. If we declare another object derive from it, in the cleanup procedure of that decendant leak to clear the IInterface references.

The test program is follow:
//===================================================================

program test_obj_inherit;
{
  bug: Interfaced Object leak in inherited Object
  environment: win2k fpc2.0.0
  date: 2005.06.13
}

{$mode objfpc}

uses
  SysUtils, Variants;

type
  TInterfacedObj = class(TInterfacedObject)
    destructor Destroy; override;
  end;

  TObj1 = object
    I: IInterface;
    constructor Create;
    procedure Which; virtual;
  end;
  PObj1 = ^TObj1;

  TObj2 = object(TObj1)
    constructor Create;
    procedure Which; virtual;
  end;
  PObj2 = ^TObj2;

  TObj3 = object(TObj1)
    //object keep a Variant
    V: Variant;
    constructor Create;
    procedure Which; virtual;
  end;
  PObj3 = ^TObj3;

var
  //used to check the interfaced object is whether or not released
  InterfacedObjReleased: Boolean;

destructor TInterfacedObj.Destroy;
  begin
    InterfacedObjReleased := True;
  end;

constructor TObj1.Create;
  begin
  end;

procedure TObj1.Which;
  begin
    WriteLn('  This is TObj1');
  end;

constructor TObj2.Create;
  begin
  end;

procedure TObj2.Which;
  begin
    WriteLn('  This is TObj2');
  end;

constructor TObj3.Create;
  begin
  end;

procedure TObj3.Which;
  begin
    WriteLn('  This is TObj3');
  end;

{==Test TObj1==}

procedure Test1_1;
  var
    Obj: PObj1;
  begin
    WriteLn('Use Object Pointer');
    New(Obj, Create);
    Obj^.I := TInterfacedObj.Create();
    Obj^.Which();
    Dispose(Obj);
  end;

procedure Test1_2;
  var
    Obj: TObj1;
  begin
    WriteLn('Use Object directly');
    Obj.Create();
    Obj.I := TInterfacedObj.Create();
    Obj.Which();
  end;

{==Test TObj2==}

procedure Test2_1;
  var
    Obj: PObj2;
  begin
    WriteLn('Use Object Pointer');
    Obj := New(PObj2, Create);
    Obj^.I := TInterfacedObj.Create();
    Obj^.Which();
    Dispose(Obj); //here, the I should be release
  end;

procedure Test2_2;
  var
    Obj: TObj2;
  begin
    WriteLn('Use Object directly');
    Obj.Create();
    Obj.I := TInterfacedObj.Create();
    Obj.Which();
  end; //afetr Test2_2 return the I should be release

{==Test TObj3==}

operator := (const I: IInterface): Variant;
  begin
    VarClear(Result);

    with TVarData(Result) do
    begin
      vtype := varunknown;
      IInterface(vunknown) := I;
    end;
  end;

procedure Test3_1;
  var
    Obj: PObj3;
  begin
    WriteLn('Use Object Pointer');
    Obj := New(PObj3, Create);
    Obj^.V := TInterfacedObj.Create();
    Obj^.Which();
    Dispose(Obj); //here, the V should be cleanup
  end;

procedure Test3_2;
  var
    Obj: TObj3;
  begin
    WriteLn('Use Object directly');
    Obj.Create();
    Obj.V := TInterfacedObj.Create();
    Obj.Which();
  end; //afetr Test3_2 return the V should be cleanup



procedure CheckReleased;
  begin
    if InterfacedObjReleased then
      WriteLn('  InterfacedObject Release, OK')
    else
      WriteLn('  InterfacedObject is *NOT* Released, Failure');

    WriteLn;

    InterfacedObjReleased := False;
  end;


begin
  WriteLn;

  Test1_1();
  CheckReleased();
  Test1_2();
  CheckReleased();

  Test2_1();  //<- The InterfacedObject leak in this call
  CheckReleased();
  Test2_2();  //<- The InterfacedObject leak in this call
  CheckReleased();

  Test3_1();
  CheckReleased();
  Test3_2();
  CheckReleased();

  WriteLn;
end.
//===================================================================


More information about the fpc-devel mailing list