例如:我做一个简单的字符串分配:
sTest := 'SET LOCK_TIMEOUT ';
但是,结果有时会变成:
sTest = 'SET LOCK'#0'TIMEOUT '
所以_被替换为0字节。
当使用FPU堆栈(fild,fistp)进行快速存储器复制(在9到32个字节的情况下移动),System.Move函数中已经看到这种情况发生了一次(复制是非常棘手的,取决于时序):
... @@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} ...
使用FPU视图和2个内存调试视图(Delphi – > View – > Debug – > cpu – > Memory)我看到它出错了…一次…无法再现…
今天早上我读了一些有关8087CW模式的信息,是的,如果这个更改成$ 27F,我得到内存损坏!通常是133F:
The difference between $133F and $027F is that $027F sets up the FPU for doing less precise calculations (limiting to Double in stead of Extended) and different infiniti handling (which was used for older FPU’s,but is not used any more).
好的,现在我发现为什么而不是什么时候!
我通过简单的检查改变了我的AsmProfiler的工作(所有功能都在进入和离开时被检查):
if Get8087CW = $27F then //normally $1372? if MainThreadID = GetCurrentThreadId then //only check mainthread DebugBreak;
我“分析”一些单位和dll的和宾果(见堆栈):
Windows.StretchBlt(3372289943,514,345,4211154027,13369376) pngimage.TPNGObject.DrawPartialTrans(4211154027,(0,0),(514,345))) pngimage.TPNGObject.Draw($7FF62450,345))) Graphics.TCanvas.StretchDraw((0,345)),$7FECF3D0) ExtCtrls.TImage.Paint Controls.TGraphicControl.WMPaint((15,0))
所以发生在StretchBlt …
现在做什么?是Windows的错误还是PNG中的错误(包含在D2007中)?
还是System.Move功能不是故障安全?
注意:只是尝试重现不起作用:
Set8087CW($27F); ssql := 'SET LOCK_TIMEOUT ';
似乎更有异国情调…但是通过“Get8087CW = $ 27F”的debugbreak,我可以在另一个字符串中重现它:
FPU第1部分:
FPU第2部分:
FPU第3部分:
FPU决赛:腐败!
注2:也许FPU堆栈必须在System.Move中被清除?
解决方法
http://brianorr.blogspot.com/2006/11/intel-pentium-d-floating-point-unit.html
http://www.dankohn.com/archives/343
http://blog.excastle.com/2007/08/28/delphi-bug-of-the-day-fpu-stack-leak/(Ritchie Annand的评论)
在我们的例子中,我们检测到错误的VPN驱动程序,并使用Delphi 7版本交换Move和FillChar,用Pascal版本替换IntToStr(Int64版本使用FPU),并且,由于我们使用FastMM,因此禁用其自定义固定因为它们比System.Move更容易受到影响。