[fpc-devel] Wrong docs: not initialized global variables
Ondrej Pokorny
lazarus at kluug.net
Sat Jul 7 10:25:49 CEST 2018
On 03.07.2018 19:53, Stefan Glienke wrote:
> SetLength should not cause anything uninitialized.
No, SetLength is not documented to clear the new initialized memory
block so the new memory block can contain whatever you want.
It is documented not to touch the existing memory block in the array.
This is the case of Delphi and FPC. See GetS_Wrong2 in the second
example below.
> It enlarges or shrinks the data and keeps any prior data as it was, new allocated memory is zeroed (at least that is how it works in the Delphi RTL and I would be very surprised if FPC would do any different).
>
> The core issue imo is temp var reuse the compiler does which causes hidden data reusage/copy which is only an issue with dynamic arrays because they don't have CoW semantic when writing to some index. So the temp variable still points to the first array which then gets passed to the next function as result. There a call to SetLength applies copy on write semantics carrying over any content from the previous array that is still in the temp variable to the newly allocated array.
>
> I think we discussed this on friday - maybe I did not make my point clear enough.
In your case I am entirely on the side with the FPC team. The result
variable is not guaranteed to be cleared:
function DoSomething (len: Integer): Vector;
begin
SetLength(Result, len); // << Result can be everything before the
SetLength call
end;
So Result can have garbage data which stays there after the SetLength call.
This happens also in Delphi. Try this code:
program Project1;
{$APPTYPE CONSOLE}
var
S_wrong, S_correct: string;
I: Integer;
function GetS_Wrong: string;
begin
Result := result+'X';
end;
function GetS_Correct: string;
begin
Result := 'X';
end;
begin
for I := 0 to 1 do
begin
S_wrong := S_wrong + GetS_Wrong;
S_correct := S_correct + GetS_Correct;
end;
Writeln('Wrong: ', S_wrong);
Writeln('Correct: ', S_correct);
Readln;
end.
Output (in Delphi XE2):
Wrong: XXX
Correct: XX
----
In case of arrays try this code in Delphi 10:
program Project1;
{$APPTYPE CONSOLE}
type
Vector = array of AnsiChar;
var
W: AnsiChar = '1';
W2: AnsiChar = '1';
C: AnsiChar = '1';
function GetS_Wrong: Vector;
begin
if Length(Result)<>1 then
SetLength(Result, 1);
Result[0] := W;
Inc(W);
end;
function GetS_Wrong2: Vector;
var
ChangeNeeded: Boolean;
begin
ChangeNeeded := Length(Result)<>1;
SetLength(Result, 1);
if ChangeNeeded then
Result[0] := W2;
Inc(W2);
end;
function GetS_Correct: Vector;
begin
SetLength(Result, 1); // set length does a copy -> correct
Result[0] := C;
Inc(C);
end;
procedure WriteVec(Vec: Vector);
var
I: Integer;
begin
for I := Low(Vec) to High(Vec) do
Write(Vec[I]);
end;
var
S_wrong, S_wrong2, S_correct: Vector;
I: Integer;
begin
for I := 0 to 1 do
begin
S_wrong := S_wrong + GetS_Wrong;
S_wrong2 := S_wrong2 + GetS_Wrong2;
S_correct := S_correct + GetS_Correct;
end;
Write('Wrong: ');
WriteVec(S_wrong);
Writeln(' expected: 12');
Write('Wrong2: ');
WriteVec(S_wrong2);
Writeln(' expected: 12');
Write('Correct: ');
WriteVec(S_correct);
Readln;
end.
The output is (Delphi 10):
Wrong: 22 expected 12
Wrong2: 11 expected: 12
Correct: 12
You see that in case of GetS_Wrong and GetS_Wrong2 even Delphi has
garbage data in Result. And it is correct like this.
Ondrej
More information about the fpc-devel
mailing list