title: Constant string parameters and the Delphi XE5 compiler for Android
body: <p>Hopefully I'm just missing something obvious, but I seem to be finding constant string arguments getting corrupted when using the Delphi XE5 Android compiler. Test code:</p>
  
  <p>1) Create a new blank mobile application project.</p>
  
  <p>2) Add a <code>TButton</code> to the form, and create an <code>OnClick</code> handler for it.</p>
  
  <p>3) Fill out the handler like so:</p>
  
  <pre><code>procedure TForm1.Button1Click(Sender: TObject);
  begin
    GoToDirectory(PathDelim + 'alpha' + PathDelim + 'beta');
    GoToDirectory(FParentDir);
  end;
  </code></pre>
  
  <p>4) In the form class declaration, add two fields and one method like this:</p>
  
  <pre><code>FCurrentPath, FParentDir: string;
  procedure GoToDirectory(const Dir: string);
  </code></pre>
  
  <p>5) Implement <code>Foo</code> and <code>GoToDirectory</code> like so:</p>
  
  <pre><code>function Foo(const S: string): Boolean;
  begin
    Result := (Now &lt;&gt; 0);
  end;
  
  procedure TForm1.GoToDirectory(const Dir: string);
  begin
    FCurrentPath := IncludeTrailingPathDelimiter(Dir);
    FParentDir := ExcludeTrailingPathDelimiter(ExtractFilePath(Dir));
    ShowMessageFmt('Prior to calling Foo, Dir is "%s"', [Dir]);
    Foo(FParentDir);
    ShowMessageFmt('After calling Foo, Dir is "%s"', [Dir]);
  end;
  </code></pre>
  
  <p>6) Compile and run on a device.</p>
  
  <p>When I do this, the first two message boxes don't indicate anything wrong, however <code>Dir</code> then gets cleared in between the third and fourth prompts. Does anyone else get this, or am I just doing something silly? (There is nothing untoward when I target Win32 for testing purposes.)</p>
  
  <p><strong>Update</strong></p>
  
  <p>For a FMX-free version, create a new blank mobile application again, but this time remove the form from the project. Then, go into the project source and add the following code:</p>
  
  <pre><code>program Project1;
  
  uses
    System.SysUtils,
    Androidapi.Log;
  
  type
    TTest = class
    private
      FCurrentPath, FParentDir: string;
      procedure GoToDirectory(const Dir: string);
    public
      procedure Execute;
    end;
  
  function Foo(const S: string): Boolean;
  begin
    Result := (Now &lt;&gt; 0);
  end;
  
  procedure TTest.GoToDirectory(const Dir: string);
  var
    M: TMarshaller;
  begin
    FCurrentPath := IncludeTrailingPathDelimiter(Dir);
    FParentDir := ExcludeTrailingPathDelimiter(ExtractFilePath(Dir));
  
    LOGE(M.AsUtf8(Format('Prior to calling Foo, Dir is "%s"', [Dir])).ToPointer);
    Foo(FParentDir);
    LOGE(M.AsUtf8(Format('After to calling Foo, Dir is "%s"', [Dir])).ToPointer);
  end;
  
  procedure TTest.Execute;
  begin
    GoToDirectory(PathDelim + 'alpha' + PathDelim + 'beta');
    GoToDirectory(FParentDir);
  end;
  
  var
    Test: TTest;
  begin
    Test := TTest.Create;
    Test.Execute;
  end.
  </code></pre>
  
  <p>To see the result, first run <code>monitor.bat</code> in the Android SDK <code>tools</code> folder; to see the wood through the trees, filter only for errors given I've used <code>LOGE</code> calls. While not every time I run this revised test app the argument gets corrupted, it does still sometimes... which is indicating a rather nasty compiler bug...</p>
  
  <p><strong>Update 2</strong></p>
  
  <p>With the second test case especially I'm convincing myself even more, so I've logged it as <a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=121321" rel="nofollow">QC 121312</a>.</p>
  
  <p><strong>Update 3</strong></p>
  
  <p>A code rather than prose version of the explanation in the accepted answer below (interface types using essentially the same reference counting mechanism as strings, only with the ability to easily track when the object is destroyed):</p>
  
  <pre><code>program CanaryInCoalmine;
  
  {$APPTYPE CONSOLE}
  
  uses
    System.SysUtils;
  
  type
    ICanary = interface
      function GetName: string;
      property Name: string read GetName;
    end;
  
    TCanary = class(TInterfacedObject, ICanary)
    strict private
      FName: string;
      function GetName: string;
    public
      constructor Create(const AName: string);
      destructor Destroy; override;
    end;
  
    TCoalmine = class
    private
      FCanary: ICanary;
      procedure ChangeCanary(const Arg: ICanary);
    public
      procedure Dig;
    end;
  
  constructor TCanary.Create(const AName: string);
  begin
    inherited Create;
    FName := AName;
    WriteLn(FName + ' is born!');
  end;
  
  destructor TCanary.Destroy;
  begin
    WriteLn(FName + ' has tweeted its last song');
    inherited;
  end;
  
  function TCanary.GetName: string;
  begin
    Result := FName;
  end;
  
  procedure TCoalmine.ChangeCanary(const Arg: ICanary);
  var
    OldName: string;
  begin
    Writeln('Start of ChangeCanary - reassigning FCanary...');
    OldName := Arg.Name;
    FCanary := TCanary.Create('Yellow Meanie');
    Writeln('FCanary reassigned - is ' + OldName + ' still alive...?');
    Writeln('Exiting ChangeCanary...');
  end;
  
  procedure TCoalmine.Dig;
  begin
    FCanary := TCanary.Create('Tweety Pie');
    ChangeCanary(FCanary);
  end;
  
  var
    Coalmine: TCoalmine;
  begin
    Coalmine := TCoalmine.Create;
    Coalmine.Dig;
    ReadLn;
  end.
  </code></pre>
  
  <p>The output is this:</p>
  
  <pre><code>Tweety Pie is born!
  Start of ChangeCanary - reassigning FCanary...
  Yellow Meanie is born!
  Tweety Pie has tweeted its last song
  FCanary reassigned - is Tweety Pie still alive...?
  Exiting ChangeCanary...
  </code></pre>
  
  <p>As such, reassigning the field drops the reference count of the previous object, which given there is no other strong reference to it, destroys it there and then before the <code>ChangeCanary</code> procedure has finished.</p>