由于更改了8087CW模式(Png + stretchblt),System.Move中的内存损坏

And*_*dré 24 delphi png stretchblt x87

我有一个奇怪的内存损坏问题.经过几个小时的调试和尝试,我想我找到了一些东西.

例如:我做一个简单的字符串赋值:

sTest := 'SET LOCK_TIMEOUT ';
Run Code Online (Sandbox Code Playgroud)

但是,结果有时会变成:

sTest = 'SET LOCK'#0'TIMEOUT '
Run Code Online (Sandbox Code Playgroud)

所以,_被0字节取代.

我在System.Move函数中看到过这种情况发生一次(复制很棘手,取决于时间),当它使用FPU堆栈(fild,fistp)进行快速内存复制时(如果要移动9到32个字节):

...
@@SmallMove: {9..32 Byte Move}
fild    qword ptr [eax+ecx] {Load Last 8}
fild    qword ptr [eax] {Load First 8}
cmp     ecx, 8
jle     @@Small16
fild    qword ptr [eax+8] {Load Second 8}
cmp     ecx, 16
jle     @@Small24
fild    qword ptr [eax+16] {Load Third 8}
fistp   qword ptr [edx+16] {Save Third 8}
...
Run Code Online (Sandbox Code Playgroud)

使用FPU视图和2个内存调试视图(Delphi - > View - > Debug - > CPU - > Memory)我看到它出错...一次......无法重现......

今天早上我读到了关于8087CW模式的一些内容,是的,如果将其更改为$ 27FI,会导致内存损坏!通常它是$ 133F:

$ 133F和$ 027F之间的区别在于$ 027F设置FPU进行不太精确的计算(限制为Double而不是Extended)和不同的infiniti处理(用于较旧的FPU,但不再使用).

好的,现在我找到了原因但不是什么时候!

我通过简单的检查改变了我的AsmProfiler的工作(所以在进入和离开时检查所有功能):

if Get8087CW = $27F then    //normally $1372?
  if MainThreadID = GetCurrentThreadId then  //only check mainthread
    DebugBreak;
Run Code Online (Sandbox Code Playgroud)

我"描述"了一些单位和dll和宾果游戏(见堆栈):

Windows.StretchBlt(3372289943,0,0,514,345,4211154027,0,0,514,345,13369376)
pngimage.TPNGObject.DrawPartialTrans(4211154027,(0, 0, 514, 345, (0, 0), (514, 345)))
pngimage.TPNGObject.Draw($7FF62450,(0, 0, 514, 345, (0, 0), (514, 345)))
Graphics.TCanvas.StretchDraw((0, 0, 514, 345, (0, 0), (514, 345)),$7FECF3D0)
ExtCtrls.TImage.Paint
Controls.TGraphicControl.WMPaint((15, 4211154027, 0, 0))
Run Code Online (Sandbox Code Playgroud)

所以它发生在StretchBlt ......

现在做什么?这是Windows的错误,还是PNG中的错误(包含在D2007中)?或者System.Move功能不是故障安全的吗?

注意:只是尝试重现不起作用:

  Set8087CW($27F);
  sSQL := 'SET LOCK_TIMEOUT ';
Run Code Online (Sandbox Code Playgroud)

它看起来更具异国情调......但是通过'Get8087CW = $ 27F'的debugbreak,我可以在另一个字符串上重现它:FPU第1部分: FPU第1部分 FPU第2部分: FPU第2部分 FPU第3部分: FPU第3部分 FPU Final:腐败!: FPU决赛:腐败!

注2:可能必须在System.Move中清除FPU堆栈?

Zoë*_*son 9

我还没有看到这个特殊问题,但如果FPU处于不良状态,Move绝对会搞砸.即使你没有做任何网络相关的事情,思科的VPN驱动程序也会让事情变得非常糟糕.

http://brianorr.blogspot.com/2006/11/intel-pentium-d-floating-point-unit.html [破]

https://web.archive.org/web/20160601043520/http://www.dankohn.com/archives/343

http://blog.excastle.com/2007/08/28/delphi-bug-of-the-day-fpu-stack-leak/(Ritchie Annand的评论)

在我们的例子中,我们检测车司机VPN和换出移动和FillChar与德尔福7版本,具有Pascal版本(Int64的版本使用FPU)取代IntToStr,并且,因为我们使用的FastMM,我们禁用其自定大小也会移动例程,因为它们比System.Move更容易受到影响.