Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Compiler/Delphi/Code Generation/Optimization    [ Add a report in this area ]  
Report #:  124017   Status: Need Feedback
[iOS] [Android] Pending references created by compiler prohibit object from being destroyed.
Project:  Delphi Build #:  19.0.14356.6604
Version:    19.2 Submitted By:   Ondrej Pokorny
Report Type:  Feature Specification issue Date Reported:  4/11/2014 3:44:27 PM
Severity:    Extreme corner case Last Updated: 4/15/2014 11:27:16 PM
Platform:    Apple mobile OS Internal Tracking #:  
Resolution: Need More Info (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: None
Description
See the code sample in the "steps".

In normal desktop compiler, the message sequence is
1. TMyObject.Destroy
2. After try-finally-end
(this is the correct behaviour).

But on mobile platforms (iOS, Android) the sequence is
1. After try-finally-end
2. TMyObject.Destroy

although NO real references are open after calling xObj.Free. There is a pending reference automatically generated by the compiler when calling MyFunc().
Steps to Reproduce:
Call the TestReferenceBug procedure and see the message box sequence.
----------------
type
  TMyObject = class(TInterfacedObject)
  public
    destructor Destroy; override;
  end;

destructor TMyObject.Destroy;
begin
  ShowMessage('TMyObject.Destroy');

  inherited;
end;

function MyFunc(const aObj: TObject): TObject;
begin
  Result := aObj;
end;

procedure TestReferenceBug;
var
  xObj: TObject;
begin
  xObj := TMyObject.Create;
  try
    MyFunc(xObj);//"virtual" reference is created here
  finally
    xObj.Free;//xObj.Destroy is not called!!!
  end;

  ShowMessage('After try-finally-end');

end;//"virtual" reference is destroyed here -> call xObj.Destroy
----------------
Workarounds
None
Attachment
None
Comments

Tomohiro Takahashi at 4/11/2014 9:25:29 PM -
Please see documentation about ARC for mobile compiler.
http://docwiki.embarcadero.com/RADStudio/XE5/en/Automatic_Reference_Counting_in_Delphi_Mobile_Compilers

Tomohiro Takahashi at 4/11/2014 9:32:31 PM -
Your code is same as this one.
----------
procedure TestReferenceBug;
var
  xObj: TObject;
  v: TObject;
begin
  xObj := TMyObject.Create;
  try
    v := MyFunc(xObj);
  finally
    xObj.Free;
  end;
  ShowMessage('After try-finally-end');
end;
----------

Ondrej Pokorny at 4/12/2014 7:14:56 AM -
I don't see any "v" variable in my original code, thus it cannot be the same.

Tomohiro Takahashi at 4/15/2014 11:27:07 PM -
How about this one? Please try it on Win32 and mobile.
------------
type
  TMyObject = class(TInterfacedObject)
  public
    destructor Destroy; override;
  end;

destructor TMyObject.Destroy;
begin
  ShowMessage('TMyObject.Destroy');
  inherited;
end;

function MyFunc(const a: IInterface): IInterface;
begin
  Result := a;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: IInterface;
begin
  x := TMyObject.Create;
  MyFunc(x);
  ShowMessage('After try-finally-end');
end;
------------

Tomohiro Takahashi at 4/11/2014 9:33:29 PM -
So, please try this one.
----------
procedure TestReferenceBug;
var
  xObj: TObject;
  v: TObject;
begin
  xObj := TMyObject.Create;
  try
    v := MyFunc(xObj);
    v := nil; // decrement reference counter
  finally
    xObj.Free; // decrement reference counter
  end;
  ShowMessage('After try-finally-end');
end;
----------

Ondrej Pokorny at 4/12/2014 7:11:53 AM -
That works.

Tomohiro Takahashi at 4/12/2014 2:50:22 AM -
So, please try another one.
----------
procedure TestReferenceBug;
var
  xObj: TObject;
  v: TObject;
begin
  xObj := TMyObject.Create;
  try
    v := MyFunc(xObj);
    v := nil; // decrement reference counter
  finally
    xObj := nil; // decrement reference counter
  end;
  ShowMessage('After try-finally-end');
end;
----------

Ondrej Pokorny at 4/12/2014 7:11:47 AM -
That works.

Server Response from: ETNACODE01