Question

There is a bug in Delphi 2006 if activating both overflow checking and optimization. The bug seems to appear only in the particular situation where a 32 bit integer is added to itself, and then a byte is added to this previous sum, in this particular order, as seen on below program.

program OptimizationBug;
{$OPTIMIZATION ON}
{$APPTYPE CONSOLE}

{$OVERFLOWCHECKS ON}
function f: integer;
var i: integer;
    b: byte;
begin
    i:=0;
    b:=1;
    Result:=i+i+b;  
end;

{$OVERFLOWCHECKS OFF}
function g: integer;
var i: integer;
    b: byte;
begin
    i:=0;
    b:=1;
    Result:=i+i+b;
end;

begin
    writeLn(f);  //wrong, prints "2" in D2006
    writeLn(g);  //good,  prints "1"
    readLn;
end.

Note: Overflow check must be encoded in the source file, not via project options. This leads us to another bug: Overflow detection via project options has no effect.

As seen on the CPU window, the optimizer gets distracted by a move with zero extension movzx (extending an 8 bit value to a 32 bit value) and by the overflow check, forgetting to load byte b on a separate register, overwriting the previous contents, with the net effect of adding b to itself instead to 2i. The upper half of below assembly code belongs to the bugged function while the bottom half to the sane construct.

OptimizationBug.dpr.20: i:=0;
00403EAC 33C0             xor eax,eax
OptimizationBug.dpr.21: b:=1;
00403EAE B201             mov dl,$01
OptimizationBug.dpr.22: Result:=i+i+b;  
00403EB0 03C0             add eax,eax
00403EB2 7105             jno $00403eb9
00403EB4 E82BF5FFFF       call @IntOver
00403EB9 0FB6C2           movzx eax,dl    //BUG: should have x-moved DL to EDX register!
00403EBC 03C0             add eax,eax     //     (and added EDX to EAX)
00403EBE 7105             jno $00403ec5
00403EC0 E81FF5FFFF       call @IntOver
OptimizationBug.dpr.23: end;
00403EC5 C3               ret 
00403EC6 8BC0             mov eax,eax
OptimizationBug.dpr.30: i:=0;
00403EC8 33C0             xor eax,eax
OptimizationBug.dpr.31: b:=1;
00403ECA B201             mov dl,$01
OptimizationBug.dpr.32: Result:=i+i+b;
00403ECC 03C0             add eax,eax
00403ECE 0FB6D2           movzx edx,dl    //OK!
00403ED1 03C2             add eax,edx     //ok
OptimizationBug.dpr.33: end;
00403ED3 C3               ret 

By the way, this code is not a pathological example, I found it while adapting D.Knuth' magnificent TeX program to modern Pascal. When checking the effect of enabling optimization and of turning off all compiler checks on the final *.exe size, it was not able to interpret the disk saved hash tables back correctly (which were generated with optimization turned off), which I traced back to above bug, which is the part which generates the tables.

The question is simple, can someone check the program on a newer version of Delphi?

Was it helpful?

Solution

The bug has not been fixed even in the latest version of Delphi, XE6. The bug does not affect the 64 bit Windows compiler. The bug is present as far back as Delphi 6, the oldest version that I can run.

I strongly recommend that you submit a QC report.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top