如果激活溢出检查和优化,Delphi 2006中有一个错误。该错误似乎只出现在特定的情况下,其中一个32位整数被添加到自身,然后一个字节添加到这个以前的和,在这个特定的顺序,如下面的程序所见。
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.
注意:溢出检查必须在源文件中编码,而不是通过项目选项。
这导致我们另一个错误:通过项目选项溢出检测没有效果。
如在cpu窗口中看到的,优化器通过零扩展movzx(将8位值扩展为32位值)和溢出检查,忘记在单独的寄存器上装载字节b,覆盖以前的内容,具有将b添加到自身而不是添加到2i的净效果。下面的汇编代码的上半部分属于bugged函数,而下半部分代表sane的构造。
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
顺便说一下,这段代码不是病理的例子,我发现它适应D.Knuth的壮丽的TeX程序到现代的帕斯卡。当检查启用优化和关闭最终* .exe大小的所有编译器检查的效果时,它无法正确解释磁盘保存的哈希表(这是通过优化关闭生成的),我追溯到上面的bug,这是生成表的部分。
问题很简单,有人可以检查程序在更新版本的Delphi?
解决方法
这个bug还没有修复,即使在最新版本的Delphi,XE6。该错误不影响64位Windows编译器。这个bug目前早在Delphi 6,我可以运行的最老的版本。
我强烈建议您提交QC报告。