11

One of my coworkers show me a code written in Delphi-XE XE Version 15.0.3953.35171, which I believe it should raise an access violation. The code is bellow:

unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm3 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
   function test:TstringList;
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.FormCreate(Sender: TObject);
var aStrList : TStringList;
begin
 aStrList := TStringList.Create;
 test;
 FreeAndNil(aStrList);
end;

function TForm3.test: TstringList;
var i:Integer;
begin
 for i:=0 to 1000 do
  Result.Add('aaa');//AV?
end;

end.

Inspecting aStrList and Result has the following results:

aStrList: TStringList $12FEDC : $42138A


Result: TStringList $12FEC4 : $B01B90

I do not understand why it is working. Result.Add should raise an access violation

LE: It seems that is working only on Debug Build Configuration.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
RBA
  • 12,337
  • 16
  • 79
  • 126
  • See [What is the default value of Result in Delphi](http://stackoverflow.com/q/5336863/576719). – LU RD Nov 20 '12 at 14:57
  • 1
    See [Documentation](http://docwiki.embarcadero.com/RADStudio/XE3/en/Program_Control). Quote `"For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result. Int64 is returned in EDX:EAX."` This means that whatever is on EAX at the function call is treated as the result parameter, as @bummi says. – LU RD Nov 20 '12 at 15:18
  • @Lurd, what you've quoted is irrelevant. `TStringList` is none of those things. – Rob Kennedy Nov 20 '12 at 17:28
  • @RobKennedy, indeed. This was what was supposed to be quoted: `"Pointer, class, class-reference, and procedure-pointer results are returned in EAX."` – LU RD Nov 20 '12 at 17:33
  • My advice: such code will emit a compiler warning. It should always be fixed as if it was an error. It could be very difficult to track at runtime... random gpf are a nightmare. – Arnaud Bouchez Nov 20 '12 at 20:24

1 Answers1

3

The Result variable in that function has not been initialized and could hold any value. Now, the implementation detail means that, in some combinations of compiler options, your code happens to run with Result referring to a valid object. But that's really just a coincidence of those implementation details.

If this were C++ then that function would exhibit undefined behaviour. Although that term does not have a formal meaning in Delphi, it can be helpful to use that term in a Delphi setting to mean the same thing as in the context of C++.

I would also make the point that even if Result did not refer to a valid string list object, your code would not be guaranteed to raise an access violation. It could be that Result points to a block of memory that just happens to look enough like a string list for that code to execute successfully.

If you do things properly, you can predict the behaviour of your program. If your code is flawed and induces undefined behaviour, then your program's behaviour becomes unpredictable. It may work. It may fail. Or that code may execute fine, but then lead to a failure later in the program's execution. And so on.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • "Result variable"? I think you're explaining an implementation detail with an implementation detail. – Sertac Akyuz Nov 20 '12 at 19:51
  • @SertacAkyuz Why so? It seems reasonable to talk about variables without specifying how they are implemented. – David Heffernan Nov 20 '12 at 19:54
  • @SertacAkyuz It is in Delphi, I believe. Why do you think it is not? – David Heffernan Nov 20 '12 at 19:58
  • Well, what I understand from a [variable](http://docwiki.embarcadero.com/RADStudio/XE3/en/Variables) is what is declared with a var. – Sertac Akyuz Nov 20 '12 at 19:59
  • @SertacAkyuz Fields of classes are variables too. And so are parameters. At least, that's how I think about them. – David Heffernan Nov 20 '12 at 20:04
  • @Seract The topic you link to starts with this text: "A variable is an identifier whose value can change at runtime." – David Heffernan Nov 20 '12 at 20:09
  • Result is a local uninitialized variable until it is returned in eax. This answer is accurate. +1 – Arnaud Bouchez Nov 20 '12 at 20:21
  • @David - 'var' is optional in field declarations but you can put it, you also put it for parameters... I know the reason is what you tell in your answer, I just don't feel it's substantial. – Sertac Akyuz Nov 20 '12 at 20:23
  • @ArnaudBouchez Thank you. I purposefully avoided going into implementation details for this answer. For example, it means the answer is meaningful when applied to 64 bit compilers, the Mac OS compiler and so on. That's why I made no mention of specific registers. – David Heffernan Nov 20 '12 at 20:24
  • @Sertac If all these things are not variables, then I don't know what they are. The [Delphi documentation](http://docwiki.embarcadero.com/RADStudio/XE3/en/Procedures_and_Functions#Function_Declarations) thinks they are variables: *In addition, the function name itself acts as a special variable that holds the function's return value, as does the predefined variable Result.* – David Heffernan Nov 20 '12 at 20:28
  • @David - I was agreeing that they were variables (fields, parameters), was not agreeing result was officially a variable. Your last comment is quite enough for me, +1.. – Sertac Akyuz Nov 20 '12 at 20:32