25

奇妙なメモリ破損の問題があります。何時間もデバッグして試した後、何かを見つけたと思います。

例: 簡単な文字列割り当てを行います。

sTest := 'SET LOCK_TIMEOUT ';

ただし、結果が次のようになる場合があります。

sTest = 'SET LOCK'#0'TIMEOUT '

したがって、_ は 0 バイトに置き換えられます。

System.Move 関数で、高速メモリ コピーに FPU スタック (fild、fistp) を使用する場合 (9 バイトから 32 バイトまで移動する場合)、これが 1 回発生するのを見たことがあります (タイミングによっては、再現が難しい場合があります)。

...
@@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 を設定して、精度の低い計算 (Extended ではなく Double に制限) と、異なる無限処理 (古い 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」のデバッグブレークにより、別の文字列で再現できました: FPU パート 1: FPUパート1 FPU パート 2: FPUパート2 FPU パート 3: FPUパート3 FPU 最終: 破損!: FPU Final: 破損しています!

注 2: System.Move で FPU スタックをクリアする必要があるのではないでしょうか?

4

4 に答える 4

10

この特定の問題は見たことがありませんが、FPU が悪い状態にある場合、Move は間違いなくめちゃくちゃになる可能性があります。Cisco の 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 ドライバーを検出し、Move と FillChar を Delphi 7 バージョンに交換し、IntToStr を Pascal バージョンに置き換え (Int64 バージョンは FPU を使用)、FastMM を使用しているため、そのカスタム修正を無効にします。サイズ移動ルーチンも、System.Move よりも影響を受けやすいためです。

于 2010-04-06T15:08:19.833 に答える
3

StretchBlt 操作を実行するときに 8087 コントロール ワードを保持しないのは、ビデオ ドライバーのバグである可能性があります。
過去に、特定のプリンター ドライバーを使用しているときに、同様の動作を見たことがあります。彼らは 8087 CW を所有していると思っていますが、それは間違っています...

Delphi の 8087 CW のデフォルト値は $1372 のようです。CW 値の詳細については、この記事を参照してください。この記事では、Michael Justin が 8087CW が故障したときに説明した状況についても説明しています。

--jeroen

于 2010-04-06T14:43:59.660 に答える
2

参考までに(他の人も同じ問題を抱えている場合に備えて):お客様のためにソフトウェアのアップグレードを行いましたが、アプリケーションの起動時にタッチスクリーン全体がロックされました!Windows が完全にフリーズしました。PC を再起動する必要がありました (電源オフ)。完全凍結の原因究明に時間がかかりました。

幸いなことに、FastMove.LargeSSEMove に AV のスタックトレースが 1 つ (1 つだけ!) ありました。fastmove で SSE の使用を無効にしたら、問題はなくなりました。

ちなみに、タッチスクリーンには S3 チップセットを搭載した VIA Nehemiah CPU が搭載されています。

そのため、FPU を使用するとメモリが破損するだけでなく、完全にフリーズすることもあります。

于 2011-06-07T12:55:20.593 に答える