Jump to content
Kryvich

Generic Dictionary and an inline variable: bug or misuse?

Recommended Posts

Hi, I try to adopt outstanding and free Pas2js transpiler to Delphi language. My main development IDE is Delphi CE Rio, so I decided to try a new Delphi syntax: generic collections and inline variables. And stumbled upon a runtime error. The code (simplified):

program TestInlineVarForDictionary;
{$APPTYPE CONSOLE}
{$R *.res}

uses SysUtils, Generics.Collections;

procedure TestDictErr;
var
  Dict: TDictionary<string,TObject>;
begin
  Dict := TDictionary<string,TObject>.Create;
  for var item in Dict do
    Writeln('Key = ', item.Key, 'Name = ', item.Value.ClassName);
end;

procedure TestDictOK;
var
  Dict: TDictionary<string,TObject>;
  item: TPair<string,TObject>;
begin
  Dict := TDictionary<string,TObject>.Create;
  for item in Dict do
    Writeln('Key = ', item.Key, 'Name = ', item.Value.ClassName);
end;

begin
  try
    //!!TestDictOK;
    TestDictErr;
  except
    on E: Exception do begin
      Writeln(E.ClassName, ': ', E.Message);
      Write('Press Enter to continue...');
      Readln;
    end;
  end;
end.

This program causes Exception class $C0000005 with message 'access violation at 0x0040a86e: write of address 0x0040a29e'. Can you confirm it? Is it a bug in the compiler or/and RTL, or am I misusing the new syntax?

It's interesting: if you uncomment TestDictOK that does enumeration in old-style, the exception will disappear!

Share this post


Link to post

Another observation. The exception occurs only if the dictionary has the key and/or value of the string type. If I change it to Integer - the exception disappears.

procedure TestDictErr_IntegerKey_OK;
var
  Dict: TDictionary<Integer,TObject>;
begin
  Dict := TDictionary<Integer,TObject>.Create;
  for var item in Dict do
    Writeln('Key = ', item.Key, 'Name = ', item.Value.ClassName);
end;

Well, I just found it. For procedure TestDictOK the compiler generates a pair of calls:

  • call @InitializeRecord
  • call @FinalizeRecord

But for procedure TestDictErr it generates only

  • call @FinalizeRecord

Program tries to finalize not initialized record and falls.

P.S. Is there a bug bounty program for Delphi? :) 

https://quality.embarcadero.com/browse/RSP-23417

Edited by Kryvich

Share this post


Link to post

OK I have a workaround for this issue. Try to specify a type of the inline variable.

procedure TestDictErr_WorkAround;
var
  Dict: TDictionary<string,TObject>;
begin
  Dict := TDictionary<string,TObject>.Create;
  for var item: TPair<string,TObject> in Dict do
    Writeln('Key = ', item.Key, ' Name = ', item.Value.ClassName);
end;

I cannot guarantee that this code will be correctly compiled. But at least there is no the runtime error anymore.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×