11

I have a procedure that takes a dynamic array TData = TArray<Byte> as a parameter.

procedure DoStuff(const Input: TData);
begin
  // do nothing
end;

And a function that returns a dynamic array.

function SomeData: TData;
begin
  Result := [1, 2];
end;

When I use the procedure in the example below, DoStuff gets the following data (1, 2, 3, 1, 3) but I get an EInvalidPointer exception after DoStuff completes.

procedure TForm1.Button1Click(Sender: TObject);
begin    
  DoStuff([1, 2, 3] + SomeData);
end;

Calling DoStuff([1, 2] + SomeData); does not result in an error, it seems to get touchy when the array is greater than 4 items. If I use a temp variable to hold the array, DoStuff still gets (1, 2, 3, 1, 2) but there is no error.

procedure TForm1.Button2Click(Sender: TObject);
var
  Temp: TData;
begin
  Temp := [1, 2, 3] + SomeData;

  DoStuff(Temp);
end;

It looks like pointer exception is related to how one of the dynamic arrays are freed when they fall out of scope.

Should I not be using dynamic arrays in this way? When working, this solved my current problem very cleanly.

I also have tried using array of Byte; instead of TArray<Byte>; but had the same result.

Full test unit:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TData = TArray<Byte>;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

procedure DoStuff(const Input: TData);
function SomeData: TData;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoStuff([1, 2, 3] + SomeData);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Temp: TData;
begin
  Temp := [1, 2, 3] + SomeData;

  DoStuff(Temp);
end;

procedure DoStuff(const Input: TData);
begin
  // do nothing
end;

function SomeData: TData;
begin
  Result := [1, 2];
end;

end.
John van Beek
  • 113
  • 1
  • 5

1 Answers1

8

Your code has no defects and any errors can only be due to compiler / RTL bugs.

Support for dynamic array literals and the dynamic array + operator was somewhat patchy when first released. These features were added in XE7 and I believe that most of the bugs were ironed out by XE8.

My guess would be that you are using XE7, or perhaps a layer version which still contains a more obscure bug than the many obvious ones from XE7.

Your options would seem to be:

  1. Update to a later Delphi version.
  2. Work around the code by avoiding use of the + operator with dynamic arrays and / or dynamic array literals.

I still use XE7 and workaround the issues with my own generic concatenation function. An example of how to do this can be found here: https://stackoverflow.com/a/15924484/505088

Such workaround help you avoid issues with the + operator, but not if the issue is with handling array literals. If your problem is with array literals then you may end up needing to use TData.Create(1, 2, 3) in place of [1, 2, 3].

If the defect is present in later versions then please submit a bug report to Embarcadero's Quality Portal.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 2
    Delphi 10.2 Berlin has the same error. Happens when calling System._DynArrayClear the 2nd time when Button1Click ends. – LU RD Oct 24 '17 at 05:47
  • Correction, 10.2 Tokyo it is. – LU RD Oct 24 '17 at 06:12
  • 1
    I can also reproduce it on 10 Seattle on Win32, but not Win64. Also `takeData(localArray + [4, 5, 6])` seems to work fine whereas `takeData([4, 5, 6] + localArray);` does not. – Günther the Beautiful Oct 24 '17 at 09:16
  • Using the `TData.Create(1, 2, 3)` in place of the constant expression `[1, 2, 3]` still causes the pointer exception. I should have mentioned that I was using XE8 but had also reproduced the issue on 10.2. – John van Beek Oct 24 '17 at 23:13
  • 1
    As other people have been able to reproduce the error I am submitting a bug report. – John van Beek Oct 24 '17 at 23:20