Who would expect this to leak memory?

Who would expect this to leak memory?

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  IFoo = interface
    procedure Bar;
  end;

  TFoo = class(TInterfacedObject, IFoo)
  private
    fProc: TProc;
  public
    constructor Create(const proc: TProc);
    procedure Bar;
  end;

constructor TFoo.Create(const proc: TProc);
begin
  inherited Create;
  fProc := proc;
end;

procedure TFoo.Bar;
begin
end;

procedure CheckException(const proc: TProc);
begin
  try
    proc();
  except
    //...
  end;
end;

procedure Main;
var
  foo: IFoo;
begin
  foo := TFoo.Create(procedure begin end);
  CheckException(procedure begin foo.Bar end);
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Comments

  1. well, never tried to use an Interface within an anonymous method?
    It is counted up for being part of the Anonymous method, but never counted down? Maybe "const" is part of the problem again, too?

    ReplyDelete
  2. I do.

    http://qc.embarcadero.com/wc/qcmain.aspx?d=101846


    program AnonMethLeak;

    {$APPTYPE CONSOLE}

    uses
      SysUtils;

    procedure Test(a: TProc);
    begin
    end;

    begin
      ReportMemoryLeaksOnShutdown := True;
      Test(procedure begin end);
    end.

    ReplyDelete
  3. Nope, Uwe. That is why I wrote the Main routine ;)

    We are facing a circular reference here because these 2 anonymous methods are internally implemented by the same class and thus share their RefCount.

    TFoo keeps alive the first one and the second one keeps alive foo. If they were implemented by different instances their RefCount would go to 0.

    ReplyDelete
  4. As good as interfaces might be, the refcount in Delphi, in conjunction with circular references, can be a nightmare to debug.

    ReplyDelete

Post a Comment