Soy miembro de un equipo que usa Delphi 2007 para una aplicación más grande y sospechamos que hay corrupción en el montón porque a veces hay errores extraños que no tienen otra explicación. Creo que la opción Rangechecking para el compilador es solo para matrices. Quiero una herramienta que dé una excepción o un registro cuando hay una escritura en una dirección de memoria que no está asignada por la aplicación.¿Cuál es la herramienta adecuada para detectar la corrupción de VMT o de montón en Delphi?
Saludos
EDIT: El error es de tipo:
Error: Acceso violación en la dirección 00404E78 en el módulo 'BoatLogisticsAMCAttracsServer.exe'. Lectura de la dirección FFFFFFDD
EDIT2: Gracias por todas las sugerencias. Lamentablemente, creo que la solución es más profunda que eso. Usamos una versión parcheada de Bold for Delphi ya que poseemos la fuente. Probablemente hay algunos errores introducidos en el marco de negrita. Sí, tenemos un registro con callstacks manejados por JCL y también traza mensajes. Por lo que una pila de llamadas con la excepción puede bloquear de esta manera:
20091210 16:02:29 (2356) [EXCEPTION] Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Call Stack:
[00] System.TObject.InheritsFrom (sys\system.pas:9237)
Call Stack:
[00] BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
[01] BoldSystem.TBoldMember.DeriveMember (BoldSystem.pas:3846)
[02] BoldSystem.TBoldMemberDeriver.DoDeriveAndSubscribe (BoldSystem.pas:7491)
[03] BoldDeriver.TBoldAbstractDeriver.DeriveAndSubscribe (BoldDeriver.pas:180)
[04] BoldDeriver.TBoldAbstractDeriver.SetDeriverState (BoldDeriver.pas:262)
[05] BoldDeriver.TBoldAbstractDeriver.Derive (BoldDeriver.pas:117)
[06] BoldDeriver.TBoldAbstractDeriver.EnsureCurrent (BoldDeriver.pas:196)
[07] BoldSystem.TBoldMember.EnsureContentsCurrent (BoldSystem.pas:4245)
[08] BoldSystem.TBoldAttribute.EnsureNotNull (BoldSystem.pas:4813)
[09] BoldAttributes.TBABoolean.GetAsBoolean (BoldAttributes.pas:3069)
[10] BusinessClasses.TLogonSession._GetMayDropSession (code\BusinessClasses.pas:31854)
[11] DMAttracsTimers.TAttracsTimerDataModule.RemoveDanglingLogonSessions (code\DMAttracsTimers.pas:237)
[12] DMAttracsTimers.TAttracsTimerDataModule.UpdateServerTimeOnTimerTrig (code\DMAttracsTimers.pas:482)
[13] DMAttracsTimers.TAttracsTimerDataModule.TimerKernelWork (code\DMAttracsTimers.pas:551)
[14] DMAttracsTimers.TAttracsTimerDataModule.AttracsTimerTimer (code\DMAttracsTimers.pas:600)
[15] ExtCtrls.TTimer.Timer (ExtCtrls.pas:2281)
[16] Classes.StdWndProc (common\Classes.pas:11583)
La parte excepción interna es la pila de llamadas en el momento de re-subió una excepción.
EDIT3: La teoría en este momento es que la Tabla de memoria virtual (VMT) se ha roto de alguna manera. Cuando esto sucede, no hay indicios de ello. Solo cuando se llama a un método se genera una excepción (SIEMPRE en la dirección FFFFFFDD, -35 decimal) pero entonces es demasiado tarde. Usted no sabe la verdadera causa del error. Cualquier sugerencia de cómo atrapar un error como este es realmente apreciada. Lo hemos intentado con SafeMM, pero el problema es que el consumo de memoria es demasiado alto incluso cuando se utiliza el indicador de 3 GB. Así que ahora trato de dar una recompensa a la comunidad SO :)
EDIT4: Una sugerencia es que según el registro a menudo hay (o incluso siempre) otra excepción antes de esto. Puede ser, por ejemplo, bloqueo optimista en la base de datos. Hemos tratado de plantear excepciones por la fuerza, pero en el entorno de prueba simplemente funciona bien.
EDIT5: La historia continúa ... Realicé una búsqueda en los registros durante los últimos 30 días. El resultado:
- "Read de dirección FFFFFFDB" 0
- "Read de dirección FFFFFFDC" 24
- "Read de dirección FFFFFFDD" 270
- "Read de dirección FFFFFFDE" 22
- " leer de dirección FFFFFFDF" 7
- "Read de dirección FFFFFFE0" 20
- "Read de dirección FFFFFFE1" 0
Así que la teoría actual es que una enumeración (hay muchos en negrita) sobrescribe un puntero. Recibí 5 hits con la dirección diferente anterior. Podría significar que la enumeración contiene 5 valores donde el segundo es el más utilizado. Si hay una excepción, debe producirse una reversión para la base de datos y se deben destruir Boldobjects. Tal vez exista una posibilidad de que no todo se destruya y una enumeración aún pueda escribir en una ubicación de dirección.Si esto es cierto, ¿es posible buscar el código por un regexpr para una enumeración con 5 valores?
EDIT6: Resumiendo, no hay solución al problema todavía. Me doy cuenta de que puedo engañarte un poco con la pila de llamadas. Sí, hay un temporizador, pero hay otros callstacks sin temporizador. Lo siento por eso. Pero hay 2 factores comunes.
- Una excepción con la lectura de la dirección FFFFFFxx.
- Parte superior de la pila de llamadas es System.TObject.InheritsFrom (SYS \ system.pas: 9237)
Este convencerme de que VilleK mejor describen el problema. También estoy convencido de que el problema está en algún lugar del marco de Bold. Pero la pregunta GRANDE es, ¿cómo se pueden resolver problemas como este? No es suficiente tener un Assert como VilleK, ya que el daño ya ocurrió y el callstack se ha ido en ese momento. Así que para describir mi visión de lo que puede provocar el error:
- En algún lugar un puntero se le asigna un valor de 1 mala, pero puede ser también 0, 2, 3, etc.
- Un objeto se asigna a ese puntero .
- Hay una llamada al método en la clase base de los objetos. Esto causa que se llame al método TObject.InheritsForm y aparezca una excepción en la dirección FFFFFFDD.
Esos 3 eventos pueden estar juntos en el código, pero también pueden usarse mucho más tarde. Creo que esto es cierto para la última llamada al método.
EDIT7: Trabajamos en estrecha colaboración con el autor de Bold Jan Norden y recientemente encontró un error en el evaluador de OCL en el marco de Bold. Cuando esto se solucionó, este tipo de excepciones disminuyó mucho, pero aún así ocasionalmente llegan. Pero es un gran alivio que esto esté casi resuelto.
Por favor, háganos saber si acerca del fallo es de diálogo violación de acceso en su programa o simplemente un comportamiento inesperado lógica. Te pregunto porque si tienes un puntero con un contenido aleatorio que apunta "en algún lugar", es probable que obtengas un error de infracción de acceso. Deberías ser realmente afortunado de tener acceso a direcciones aleatorias y obtener solo errores lógicos. – Maksee
Como escribí en la última edición, pensamos que el VMT se rompió, tal vez por un puntero roto, por lo que más adelante, cuando la aplicación llama a un método virtual, genera una excepción. –
¿Es esta una aplicación multihilo? – Nat