[fpc-devel] Managed Types, Undefined Bhaviour

Stefan Glienke sglienke at dsharp.org
Fri Jun 29 17:57:58 CEST 2018


Let me add some information to this issue - as I think this is one - before this drifted into the interface chaining thing:

When you execute this code in Delphi it will print 0 while on FPC it prints 42:

type
  Vector = array of integer;

function DoSomething (len: Integer): Vector;
begin
  SetLength(Result, len);
end;

var
  A, B: Vector;
begin
  A := DoSomething(3);
  A[0] := 42;
  B := DoSomething(4);
  Writeln(B[0]);
end.


This is the case as FPC reuses the same temp variable for both calls and thus still points to an allocated array from the first call which it just enlarges by one. Delphi in this case does not directly pass A and B but does temp variables for both (it does that because A and B are global variables).

When you move this code to a routine like this:

procedure Main;
var
  A, B: Vector;
begin
  A := DoSomething(3);
  A[0] := 42;
  B := DoSomething(4);
  Writeln(B[0]);
end;

begin
  Main;
end.

both Delphi and FPC behave the same - both directly pass A and B do DoSomething because they are local variables that can not be affected by any other code running at the same time.

While this might look as something that does not have any serious implication it actually might have.

Change the code to following:

type
  TFoo = class
    A, B: Vector;
  end;

procedure Main;
var
  foo: TFoo;
begin
  foo := TFoo.Create;
  foo.A := DoSomething(3);
  foo.A[0] := 42;
  foo.B := DoSomething(4);
  Writeln(foo.B[0]);
end;


Now we are back to using temp variables (both Delphi and FPC do) but FPC again reuses its temp variable for A and B while Delphi uses different ones. Now for some integer this might not be a big issue but imagine you have something else in these arrays (for example any managed type like an interface).
Not having properly cleared B because it still uses the temporary content from A might cause some issues.

> On 28 June 2018 at 20:06 Jonas Maebe <jonas at freepascal.org> wrote:
> 
> 
> On 28/06/18 18:45, Willibald Krenn wrote:
> > 
> > type  Vector = array of integer;
> > function DoSomething (len: longint): Vector; begin
> >    SetLength (result,len); // whatever
> > end;
> > 
> > var  A,B: Vector;
> > begin
> >    A := DoSomething(3);
> >    // changing A here will influence B below,
> >    // which seems ok to some as
> >    // "managed types are not initialized when
> >    // calling DoSomething and this is documented
> >    // - so anything goes and stop whining".
> >    B := DoSomething(3);
> > end.
> > 
> > I strongly believe that the behaviour as currently implemented is wrong 
> > and here is why.
> > (1) When assigning "result" to A, refcount of result needs to go down 
> > and, hence, the local var needs to be freed/invalidated. (Result goes 
> > out of scope.)
> 
> For performance reasons, managed function results are implemented as 
> call-by-reference parameters. This is also the case in Delphi: 
> http://docwiki.embarcadero.com/RADStudio/Berlin/en/Program_Control#Handling_Function_Results
> 
> Therefore the function result's scope is the caller of the function, not 
> the function itself.
> 
> > (3) The behaviour is incompatible to Delphi (tested 10.2.3 vs. Lazarus 
> > 1.8.0).
> 
> It is compatible with Delphi. See e.g. 
> https://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg43050.html
> 
> > Delphi shows the expected behaviour of treating A and B as distinct.
> 
> That's because your example gets optimized better by Delphi than by FPC: 
> Delphi directly passes A resp. B as the function result "var" parameter 
> to the function calls in your example, while FPC passes a/the same 
> temporary variable to them and then assigns this temprary variable to A/B.
> 
> If you have more complex code where the Delphi compiler cannot be 
> certain that the variable to which you assign the function result isn't 
> used inside the function as well, it will behave in a similar way (as 
> discussed in the StackOverflow posts linked from the message above).
> 
> 
> Jonas
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel



More information about the fpc-devel mailing list