2010-04-06 6 views
23

Tengo un extraño problema de corrupción de memoria. Después de muchas horas de depuración e intento, creo que encontré algo.Corrupción de la memoria en System.Move debido a un cambio en el modo 8087CW (png + stretchblt)

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 ' 

Así, el _ es reemplazado por un 0 bytes.

He visto esto una vez (la reproducción es complicada, depende del tiempo) en la función System.Move, cuando utiliza la pila FPU (fild, fistp) para la copia de memoria rápida (en el caso de 9 hasta 32 bytes 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} 
... 

Usando la vista FPU y 2 vistas de depuración de memoria (Delphi -> Ver -> depuración -> CPU -> memoria) vi que va mal ... una vez ... no podía reproducirse sin embargo ...

Esta mañana he leído algo sobre el modo 8087CW, y sí, si esto se cambia a $ 27FI ¡se daña la memoria! Normalmente es $ 133f:

La diferencia entre $ 133f y $ 027F es que $ 027F establece la FPU para hacer cálculos menos precisos (limitando a dobles en lugar de extendido) y gastos de envío diferente Infiniti (que fue utilizado para FPU anteriores, pero ya no se usa).

bien, ahora he encontrado la razón por pero no cuando !

he cambiado el trabajo de mi AsmProfiler con una sencilla comprobación (por lo que todas las funciones se controlan a entrar y salir):

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

I "perfilado" algunas unidades y 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 un error de Windows o un error en PNG (incluido en D2007)? ¿O la función System.Move no es a prueba de fallas?

Nota: simplemente tratando de reproducir no funciona:

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

parece ser más exótico ... Pero por DebugBreak en 'Get8087CW = $ 27F' que pueda reproducirla en una otra cadena : FPU parte 1: FPU part 1 FPU parte 2: FPU part 2 FPU parte 3: FPU part 3 FPU final: corrupto !: FPU Final: corrupt!

Nota 2: Quizás la pila de FPU se debe borrar en System.Move?

+0

+1 por el buen trabajo en la investigación. No sé la respuesta, pero mi estrategia de solución de problemas siempre es simplificar el problema eliminando las posibilidades. Vea si puede gobernar el PNG dentro o fuera eliminándolo o reemplazándolo con una lib más nueva. –

+0

Pregunta relacionada: http://stackoverflow.com/questions/1466229/what-can-cause-system-move-to-occasionaly-give-wrong-results – mghie

Respuesta

8

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. El controlador VPN de Cisco puede estropear las cosas horriblemente, incluso si no está haciendo nada relacionado con la red.

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

En nuestro caso, detectar el controlador VPN buggy y intercambiar Mover y FillChar con las versiones de Delphi 7, reemplace IntToStr con una La versión de Pascal (la versión Int64 usa la FPU) y, como usamos FastMM, también deshabilitamos sus rutinas de movimiento de tamaño fijo, ya que son aún más susceptibles que System.Move.

+0

Gracias, ya me preguntaba si podría haber más situaciones como esta , entonces sí ... :-( Pero esto me da malos presentimientos sobre FPU en general: si tienes cálculos científicos o comerciales muy importantes, ¿cómo puedes estar 100% seguro de que los resultados son correctos? Es decir: si ejecutas o use una función externa, tiene un riesgo adicional. Ahora es PNG o una tarjeta de video que puede dañar la FPU, pero también Cisco o el controlador de audio pueden hacerlo ... –

+0

@ André con el estado actual de las cosas, la única forma razonable de hacerlo asegurar que tienen razón es mediante el uso de una instalación simple de Windows (sin controladores de terceros), y solo su software. –

3

Podría ser un error en su controlador de video que no conserva la palabra de control 8087 cuando realiza la operación de StretchBlt.
En el pasado, he visto un comportamiento similar cuando uso ciertos controladores de impresora. Creen que poseen el 8087 CW y están equivocados ...

Tenga en cuenta que el valor predeterminado del 8087 CW en Delphi parece $ 1372; para una explicación más detallada de los valores de CW, vea this article: también explica una situación que Michael Justin describió cuando su 8087CW recibió una manguera.

--jeroen

2

Solo para su información (en caso de que otros también tengan el mismo problema): realizamos una actualización de nuestro software para un cliente y la pantalla táctil completa se bloqueó cuando nuestra aplicación se inició. ¡Windows estaba completamente congelado! La PC tuvo que ser reiniciada (apagado). Tomó algún tiempo descubrir la causa del congelamiento completo.

Afortunadamente tuvimos una (solo 1) stacktrace de un AV en FastMove.LargeSSEMove. Inhabilité el uso de SSE en fastmove y el problema desapareció.

Por cierto: la pantalla táctil tiene una CPU VIA Nehemiah con un chipset S3.

¡Así que no solo puede obtener daños en la memoria cuando usa la FPU, sino también una congelación completa!

Cuestiones relacionadas