Delphi 2006 优化漏洞

24

如果同时激活溢出检查和优化,则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。下面汇编代码的上半部分属于出错的函数,而下半部分属于正常构造。

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程序改编为现代Pascal时找到了它。当检查启用优化和关闭所有编译器检查对最终*.exe大小的影响时,它不能正确地解释磁盘保存的哈希表(这些哈希表是在关闭优化的情况下生成的),我追溯到上述错误,这部分是生成表格的部分。

问题很简单,有人能在更新的Delphi版本上检查一下这个程序吗?


2
我已经在XE4中进行了测试,结果是一样的: 2然后1。 - Graymatter
感谢您的测试,Gray。 - Marcelo Bergweiler
我已在XE3中进行了测试,结果是相同的2和1。但如果我切换到64位,则会打印正确的结果。 - justyy
1个回答

9

即使在最新版的Delphi XE6中,这个漏洞仍未修复。该漏洞不会影响64位Windows编译器。该漏洞可追溯到Delphi 6,这是我能运行的最旧版本。

我强烈建议您提交QC报告。


5
生成了QC报告,David。感谢你的测试。 - Marcelo Bergweiler
4
我投票支持那个 QC 并添加了这个 bug 在 XE6 中仍然存在的信息。 - Sir Rufo
7
历史注:它也存在于 Delphi 2 到 Delphi 5 中。 - gammatester
@gammatester 谢谢。我手头没有我的 Delphi 2!听起来像是这个 bug 是在第一个版本的 32 位编译器中引入的,并且一直保持到现在!! - David Heffernan
根据QC的记录,该漏洞最终于2014年7月31日被消除。 - Marcelo Bergweiler
意思是Delphi XE7,发布于2014年9月2日,不受此错误的影响。 - Marcelo Bergweiler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接