我有一个奇怪的内存损坏问题。经过几个小时的调试和尝试,我想我找到了一些东西。
例如:我做了一个简单的字符串赋值:
sTest := 'SET LOCK_TIMEOUT ';
但是,结果有时会变成:
sTest = 'SET LOCK'#0'TIMEOUT '
因此,_ 被一个 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}
...
使用 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;
我“分析”了一些单元和 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))
所以它发生在 StretchBlt...
现在做什么?是 Windows 的错误,还是 PNG 中的错误(包含在 D2007 中)?或者 System.Move 函数不是故障安全的?
注意:简单地尝试重现是行不通的:
Set8087CW($27F);
sSQL := 'SET LOCK_TIMEOUT ';
它似乎更具异国情调......但是通过'Get8087CW = $27F'上的debugbreak,我可以在另一个字符串上重现它:FPU part 1: FPU part 2: FPU part 3: FPU Final:损坏!:
注意 2:也许 FPU 堆栈必须在 System.Move 中清除?