corrupción de memoria en System.Move debido al modo de 8087CW cambiada (png + StretchBlt)

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

  •  24-09-2019
  •  | 
  •  

Pregunta

Tengo extraño problema de corrupción de memoria. Después de muchas horas de depuración y tratando Creo que he encontrado algo.

Por ejemplo: hago un simple asignación de cadena:

sTest := 'SET LOCK_TIMEOUT ';

Sin embargo, el resultado veces se convierte en:

sTest = 'SET LOCK'#0'TIMEOUT '

Por lo tanto, el _ es reemplazado por un 0 bytes.

he visto que esto ocurra una vez (reproducción es complicado, depende de la sincronización) en la función System.Move, cuando se usa la pila FPU (Fild, FISTP) para la copia de memoria rápida (en el caso de 9 y 32 bytes para mover ):

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

Uso de la vista FPU y 2 vistas de depuración de memoria (Delphi -> Ver -> Depuración -> CPU -> Memoria) lo vi saliendo mal ... una vez ... no podía reproducirse sin embargo ...

Esta mañana he leído algo sobre el modo de 8087CW, y sí, si esto se convierte en $ 27F consigo daños en la memoria! Normalmente es $ 133f:

  

La diferencia entre $ 133f y $ 027F es que $ 027F conjuntos hasta la FPU para hacer cálculos menos precisos (limitando al doble en lugar de extendido) y gastos de envío diferente Infiniti (que fue utilizado para mayores FPU de, pero no se utiliza ningún más).

Bien, ahora he encontrado ¿Por qué pero no cuando

Me cambió el trabajo de mi AsmProfiler con una sencilla comprobación (por lo que todas las funciones son controlados en entrar y salir):

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

"perfilado" y algunas unidades de DLL y bingo (ver pila):

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

Por lo que está sucediendo en StretchBlt ...

¿Qué hacer ahora? ¿Es una falla de Windows o un error en PNG (incluido en D2007)? O es la función System.Move no a prueba de fallos?

Nota: , simplemente intentando reproducir no funciona:

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

Parece que es más exótico ... Pero por DebugBreak en 'Get8087CW = $ 27F' que pueda reproducirla en una otra cadena: FPU parte 1: FPU parte 1 FPU parte 2: FPU parte 2 FPU parte 3: FPU parte 3 FPU final: corruptos !: FPU final:! Corrupta

Nota 2:? Tal vez la pila FPU debe ser despejado en el System.Move

¿Fue útil?

Solución

No he visto este tema en particular, sino que se mueven sin duda puede llegar en mal estado si el FPU está en mal estado. controlador VPN de Cisco puede enredar las cosas terriblemente, incluso si usted no está haciendo nada relacionado con la red.

http: //brianorr.blogspot .com / 2006/11 / Intel Pentium-d-punto flotante unit.html [roto]

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/ (los comentarios de Ritchie Annand)

En nuestro caso detectamos el conductor de carro VPN y de intercambio a cabo Mover y FillChar con las versiones de Delphi 7, reemplace IntToStr con una versión Pascal (Int64-versión utiliza la FPU), y, ya que estamos utilizando FastMM, desactivamos su costumbre rutinas de movimiento tamaño fijo también, ya que son más susceptibles que los System.Move.

Otros consejos

Podría ser un error en el controlador de vídeo que no conserva la palabra de control 8087 cuando se realiza la operación StretchBlt.
En el pasado he visto un comportamiento similar cuando se utilizan ciertos controladores de impresora. Ellos piensan que son dueños de la CW y 8087 están equivocados ...

Tenga en cuenta el valor por defecto del 8087 CW en Delphi parece $ 1372; para una explicación más detallada de los valores de CW, ver este artículo: . también explica una situación que Michael Justin describe cuando su 8087CW consiguió una manguera

- Jeroen

Sólo para su información (en caso de que alguno más tiene el mismo problema también): hicimos una actualización de nuestro software para un cliente, y la pantalla táctil completa encerrado cuando se inició nuestra aplicación! Windows fue completamente congelado! El PC ha tenido que reiniciar (la alimentación). Tomó un poco de tiempo para averiguar la causa de la congelación completa.

Afortunadamente, tenía una (sólo 1!) StackTrace de un AV en FastMove.LargeSSEMove. He desactivado el uso de la ESS en fastmove, y el problema se ha ido.

Por cierto:. Pantalla táctil tiene una CPU a través de Nehemías con un conjunto de chips S3

Así que no sólo se puede obtener corrupción de memoria cuando se utiliza el FPU, sino también una congelación completa!

Para aquellos que todavía está interesado en esto: Hay otra posible causa de problemas:

Delphi Rio todavía se envía con una versión ASM roto de Move.

tuve el placer de correr en ese error hoy en día, por suerte tuve un caso de prueba reproducible. La cuestión es esta pieza de código:

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

Referencias

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top