Reported by Jani Järvinen; checked by Reinier Sterkenburg
Problem example:
program Project1;
{$OPTIMIZATION ON}
Uses Dialogs,SysUtils;
Var I, J: Integer;
begin
J := 123;
A: I := I+J;
B: I := J-I; { compiler warning here: "I" not initialized }
ShowMessage(IntToStr(I));
end.
Above, this simple program should display zero as its result. On statement
A, the program relies on the fact that global variables initially have
a zero value (I, J both equal zero) and thus the addition is unnecessary
and could be an assignment instead (I := J). On B, the code does a substract,
and the result should be zero. However, if optimization is on, a garbage
result (usually something like -5636096) will occur.
People have questioned where it says that global variables are initialized
to zero. Well, on page 47, fourth paragraph of the Language
Guide (Delphi 2?) it says:
"If a global variable declaration does not explicitly specify an
initial value, the memory occupied by the variable will initially be set
to zero".
This has been a well-known language feature since BP 7.0, and it is still
mentioned in the Delphi 4 on-line help (topic "global variables"). This is also
known as "data segment clearing" and will make all non-initialized
variables to be set to zero. For example, pointers will be set to nil and
strings to empty ('').
Cause:
Because the compiler optimizes the variables to be on CPU registers and
not in memory, the register for I is not cleared. If you look at the assembled
code, you can see that the EBX register is not cleared and contains a garbage
value. The reason for this seems to be the incorrect warning that variable
I might not be initialized on statement B (shouldn't the warning occur
on statement A?) and thus the optimizer gets confused producing bad code.
Stack or memory based variables seem to work OK in this kind of situations. |