Speicherbeschädigung in System.Move aufgrund geänderter 8087CW Modus (png + StretchBlt)

StackOverflow https://stackoverflow.com/questions/2584654

  •  24-09-2019
  •  | 
  •  

Frage

Ich habe seltsame einen Speicherfehler Problem. Nach vielen Stunden Debuggen und versuchen, ich glaube, ich etwas gefunden.

Zum Beispiel: Ich habe eine einfache String-Zuordnung:

sTest := 'SET LOCK_TIMEOUT ';

Doch das Ergebnis manchmal wird:

sTest = 'SET LOCK'#0'TIMEOUT '

Also, das _ wird durch einen 0-Byte ersetzt.

Ich habe dieses Ereignis gesehen einmal (Wiedergabe ist schwierig, abhängig von Timing) in der System.Move Funktion, wenn es den FPU-Stapel (Fild, FISTP) verwendet für die schnelle Speicherkopie (im Fall von 9 bis 32 Bytes zu bewegen ):

...
@@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}
...

Mit der FPU Ansicht und 2 Speicher Debug-Ansichten (Delphi -> Ansicht -> Debug -> CPU -> Memory) Ich sah es falsch gehen ... wenn ... konnte aber nicht reproduzieren ...

An diesem Morgen las ich etwas über den 8087CW Modus, und ja, wenn dies in 27F $ geändert wird erhalte ich Speicher Korruption! Normalerweise ist es $ 133F:

  

Der Unterschied zwischen $ 133F und 027F $ ist, dass $ 027F richtet die FPU dafür weniger präzise Berechnungen (limitierend Doppel anstelle von Extended) und verschiedene infiniti Handling (die für ältere FPU die verwendet wurde, aber wird verwendet, nicht mehr).

Okay, jetzt habe ich Warum , aber nicht , wenn

Ich habe die Arbeit meines AsmProfiler mit einer einfachen Überprüfung (so alle Funktionen betreten und verlassen checked at):

if Get8087CW = $27F then    //normally $1372?
  if MainThreadID = GetCurrentThreadId then  //only check mainthread
    DebugBreak;

I "profiliert" einige Einheiten und DLL und Bingo (siehe Stapel):

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))

So geschieht es in StretchBlt ...

Was jetzt tun? Ist es ein Fehler von Windows, oder um einen Fehler in PNG (in D2007 enthalten)? Oder ist die System.Move Funktion nicht ausfallsicher?

Hinweis: einfach zu reproduzieren versucht, funktioniert nicht:

  Set8087CW($27F);
  sSQL := 'SET LOCK_TIMEOUT ';

Es scheint, exotischere zu sein ... Aber auf Debugbreak ‚Get8087CW = $ 27F‘ ich es auf einer anderen Saite reproduzieren könnte: FPU Teil 1: FPU Teil 1 FPU Teil 2: FPU Teil 2 FPU Teil 3: FPU Teil 3 FPU Final: korrupt !: FPU Finale: korrupt

Hinweis 2: Vielleicht ist der FPU-Stapel muss im System.Move gelöscht werden

War es hilfreich?

Lösung

Ich habe nicht dieses besondere Problem gesehen, aber auf jeden Fall bewegen verkorkste erhalten kann, wenn die FPU in einem schlechten Zustand ist. Ciscos VPN-Treiber kann die Dinge vermasselt schrecklich, auch wenn Sie nichts Netzwerk im Zusammenhang tun.

http: //brianorr.blogspot .com / 2006/11 / Intel-Pentium-D-Gleitkommazahl-unit.html [gebrochen]

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/ (Kommentare von Ritchie Annand)

In unserem Fall erkennen wir die Buggy VPN-Treiber und die Swap-Verschieben und FillChar mit den Delphi 7-Versionen ersetzen IntToStr mit einer Pascal-Version (Int64-Version verwendet die FPU), und da wir FastMM verwenden, wir deaktivieren auch seine individuelle Größe bewegen Routinen festgelegt, da sie noch anfälliger als System.Move sind.

Andere Tipps

Es könnte ein Fehler in Ihrem Grafiktreiber, die nicht das 8087 Steuerwort nicht bewahrt, wenn er die StretchBlt Operation durchführt.
In der Vergangenheit habe ich ein ähnliches Verhalten beobachtet, wenn bestimmte Druckertreiber verwenden. Sie denken, sie besitzen die 8087 CW und sind falsch ...

Beachten Sie den Standardwert des 8087 CW in Delphi scheint $ 1372; Eine ausführlichere Erläuterung der CW-Werte finden Sie unter dieser Artikel . es erklärt auch, eine Situation, dass Michael Justin beschrieben, als seine 8087CW abgespritzt wurde

- jeroen

Nur zur Information (bei einigen hat sonst gleiche Problem auch): wir ein Upgrade unserer Software für einen Kunden haben, und die komplette Touchscreen gesperrt, wenn unsere Anwendung gestartet wurde! Fenster wurde komplett eingefroren! Der PC werden mußte (ausgeschaltet) neu gestartet. Es dauerte einige Zeit, um herauszufinden, die Ursache für das vollständige Einfrieren.

Zum Glück hatten wir ein (nur 1!) Stacktrace einer AV-in FastMove.LargeSSEMove. Ich die Verwendung von SSE in fastmove deaktiviert, und das Problem ist weg.

Übrigens:. Touchscreen verfügt über eine VIA Nehemiah CPU mit einem S3-Chipsatz

So können Sie nicht nur Speicher Verfälschungen erhalten, wenn die FPU verwenden, sondern auch ein komplettes Einfrieren!

Für Interessenten noch in dieser: Es gibt noch eine weitere mögliche Ursache für Probleme:

Delphi Rio noch Schiffe mit einer gebrochenen ASM-Version von Move.

Ich hatte das Vergnügen in diesen Bug heute zu laufen, zum Glück hatte ich einen reproduzierbaren Testfall. Das Problem ist, dieses Stück Code:

* ***** BEGIN LICENSE BLOCK *****
 *
 * The assembly function Move is licensed under the CodeGear license terms.
 *
 * The initial developer of the original code is Fastcode
 *
 * Portions created by the initial developer are Copyright (C) 2002-2004
 * the initial developer. All Rights Reserved.
 *
 * Contributor(s): John O'Harrow
 *
 * ***** END LICENSE BLOCK ***** *)

// ... some less interesting parts omitted ...

@@LargeMove:
        JNG     @@LargeDone {Count < 0}
        CMP     EAX, EDX
        JA      @@LargeForwardMove

        // the following overlap test is broken
        // when size>uint(destaddr), EDX underflows to $FFxxxxxx, in which case 
        // we jump to @LargeForwardMove even if a backward loop would be appropriate
        // this will effectively shred everything at EDX + size
        SUB     EDX, ECX              // when this underflows ...
        CMP     EAX, EDX              // ... we also get CF=1 here (EDX is usually < $FFxxxxxx)
        LEA     EDX, [EDX+ECX]        // (does not affect flags)
        JNA     @@LargeForwardMove    // ... CF=1 so let's jump into disaster!

        SUB     ECX, 8 {Backward Move}
        PUSH    ECX
        FILD    QWORD PTR [EAX+ECX] {Last 8}
        FILD    QWORD PTR [EAX] {First 8}
        ADD     ECX, EDX
        AND     ECX, -8 {8-Byte Align Writes}
        SUB     ECX, EDX

Referenzen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top