Consider these two standalone functions

Consider these two standalone functions
function CaptureList: TArray;
procedure LogList(const aList: TArray);
and the two following use cases:

This one works,

procedure TSomeClass.Case1;
var
List: TArray;
begin
List := CaptureList;
LogList(CaptureList);
end;

but this one fails.

procedure TSomeClass.Case2;
begin
LogList(CaptureList);
end; <- EInvalidPointer in _DynArrayClear on exit

Does anyone see any potential reason why the second fails?

Berlin 10.1 Update 2 Enterprise

Comments

  1. I have no 10.1 here, but will it work if you declare the method this way?
    procedure LogList(aList: TArray); // removed the const

    ReplyDelete
  2. Not sure, haven't tried. It would defeat the purpose of not duplicating the dynamic array while passing it down the line, though.

    ReplyDelete
  3. Do you have a complete failing example in a short unit or so?

    ReplyDelete
  4. Need the code from these two routines. Without that it is impossible to identify the defect.

    ReplyDelete
  5. As always - it is complicated. Multiple threads, multiple units, and the values of each element of the list is copied line by line into elements of a separate type (record with a string field) at the innermost point. The record will exist for a longer period of time after the calls are completed.

    I just find it odd that it works with a local list, but not without it.

    ReplyDelete
  6. Works fine for me. Does this work for you? If it does, then it's something else and you've provided not enough information.

    type
    TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    private
    { Private declarations }
    protected
    { Protected declarations }
    public
    { Public declarations }
    procedure Case1;
    procedure Case2;
    end;

    implementation

    {$R *.dfm}

    function CaptureList: TArray;
    begin
    Result := TArray.Create('One', 'Two', 'Three');
    end;

    procedure LogList(const aList: TArray);
    begin
    Showmessage(aList[1]);
    end;

    procedure TForm1.Case1;
    var
    List: TArray;
    begin
    List := CaptureList;
    LogList(CaptureList);
    end;

    procedure TForm1.Case2;
    begin
    LogList(CaptureList);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    Case1;
    Case2;
    end;

    ReplyDelete
  7. Lars Fosdal If it happens in multithreaded environment then I guess is is because the const is causing the refcount to not be increased for the duration of that routine to run which means that while some other code runs it might reach zero too early and the array gets finalized which causes the invalid pointer exception.

    ReplyDelete
  8. Stefan Glienke Sounds plausible, but why does it work when using an explicit local variable?

    ReplyDelete
  9. Lars Fosdal Because no other threads are using the same local variable? The second code block you posted in OP suggests it's shared if not local.

    ReplyDelete
  10. Lars Fosdallocal variable increments refcounter and prevents array from destroying during Case1 execution

    ReplyDelete
  11. If I am not mistaken, dynamic arrays are like interfaces, as they both have refcounts (interfaces refcounts are visible, which dynamic arrays aren't). Here is a discussion about interfaces and refcounts - plus.google.com - Please vote for http://qc.embarcadero.com/wc/qcmain.aspx?d=90482 You need to... - just apply it dynamic arrays.

    ReplyDelete
  12. procedure LogList(aList: TArray);

    would indeed solve the problem. It would not lead to any duplication. This is a dynamic array rather than an open array. What would be copied by value is the reference to the array. And that copy requires reference counting which is what keeps your array alive.

    I don't much care for it though. I'd much rather that the compiler would hold a reference for duration of the function call, from the outside. That would allow the use of const and not force all consumers of the function to increment reference counts needlessly.

    ReplyDelete

Post a Comment