2010-09-09 22 views
6

Estoy buscando consejos sobre cómo depurar un bloqueo en una aplicación que utiliza los contenedores MS XML en Delphi VCL. Sospecho que la corrupción de memoria, o algún tipo de cosa malvada y oscura ocurre entre objetos e interfaces, como errores de recuento de referencias o corrupción de montón. La pregunta es, en efecto: ¿cómo puedo depurar una falla?objetos Delphi, objetos NIL e interfaces

Este código particular hace un uso interno fuerte y se extiende en la base XmlIntf Interfaces (IXMLNode). ISomethingCustom es una interfaz que extiende IXMLNode. El problema ocurre cuando fallamos en algún lugar de una función recursiva que pasa un ISomethingCustom que también es (o admite también, en términos de interfaz) IXMLNode.

boolean UtilityFunction(aNode: ISomethingCustom):Boolean; 
    begin 
     if not Assigned(aNode) then exit; // this works. great. 
     if not Assigned(aNode.ParentNode) then exit; // this DOES NOT WORK. 
    // code that blows up if aNode.ParentNode is not assigned. 
    end; 

la situación es que el ánodo es también IXMLNode, y se le asigna el valor IXMLNode.ParentNode (no nula), y sin embargo, apunta a un objeto COM que pueden haber sido liberado, destruido o dañado de alguna manera. Estoy tratando de averiguar QUÉ está sucediendo cuando un puntero de interfaz puede parecer válido, pero el objeto detrás de él se ha numerado de alguna manera.

Comprobación Asignado (aNode.ParentNode) devuelve verdadero, aun cuando, si tuviera que intentar un elenco en el depurador (en tiempo de ejecución solamente, no en el código), así:

  1. Inspeccionar/Evaluar ánodo
  2. una inspección/evaluar TInterfacedObject (ánodo) .ClassName (obras en Delphi 2010, al menos!)
  3. ahora fundido TWhateverClassNameYouGotBefore (ánodo).
  4. En el depurador ahora veo que esto es NIL. Lo que puede significar que está fallando la función mágica "fundición de interfaz de nuevo a objeto" que es nueva en delphi 2010.

Creo que estoy intentando depurar un problema donde los montones están dañados, o los objetos COM están corruptos en el montón, debido a un problema de conteo de referencias.

Realmente creo que nadie debería tener la situación donde una interfaz parece válida, pero el objeto de abajo ha sido eliminado. Realmente me gustaría saber qué hacer y qué está sucediendo.

+0

Comprobando asignado (aNode.ParentNode) devuelve TRUE, incluso cuando TNode (aNode) .ParentNode es realmente NIL. <- ¿Está transfiriendo una interfaz a una referencia de objeto? –

+0

Debe estar haciendo algo roto. No hacer ningún casting intencionalmente hasta que noté que algo está roto, entonces estoy haciendo moldes en la expresión de evaluación en el depurador, solo para ver si puedo ver algo sobre lo que hay detrás de la interfaz. :-) –

Respuesta

9

Aunque no se ha mostrado en su código, su los comentarios parecen indicar que estás modificando la variable de la interfaz a un tipo de clase. Eso no está permitido. He descrito por qué:

referencias de interfaz y referencias a objetos no apuntan a las mismas cosas. Por lo tanto, llamar a un método en uno cuando el compilador cree que tiene el otro producirá resultados inesperados. Tuviste mala suerte porque el código siguió ejecutándose en lugar de bloquearse con una infracción de acceso, lo que hubiera sido una indicación más grande de que estabas haciendo algo mal.

Mi artículo anterior concluye sugiriendo que use la función JclSysUtils​.GetImplementorOfInterface del JCL si tiene una interfaz implementada por Delphi y la interfaz no ofrece ninguna función propia para mostrar el objeto subyacente.

+1

La conversión de un puntero de interfaz a su puntero de clase de implementación es una nueva característica en Delphi 2010 o XE, no recuerdo cuál fue la que la introdujo. –

+0

Solo estaba volviendo al Objeto porque noté que dicho molde daba como resultado un valor NIL, y me pareció curioso. En tiempo de ejecución, en realidad no hago un lanzamiento de ese tipo, excepto como código de depuración que eliminé rápidamente después de descubrir lo que dices. Todavía se cuelga, lo que significa que tengo corrupción de montón, o algo más va mal. –

+0

He reescrito mi pregunta casi por completo, espero que me aclare la naturaleza de mi situación. Tus "punteros" de arriba me dejaron claro algo que antes no entendía, lo cual es genial. Dado mi completo desconocimiento de la situación, me pregunto si esta pregunta puede ser rescatada, o si debería volver a escribirla cuando sepa lo que está sucediendo más. –

0

conjetura salvaje: ¿Ha tratado de poner aNode.ParentNode en una variable local y utilizarlo en el resto de la Utilityfunction:

function UtilityFunction(aNode: ISomethingCustom): Boolean; 
    var 
    lParentNode: INode; 
    begin 
     if not Assigned(aNode) then exit; // this works. great. 
     lParentNode := aNode.ParentNode; 
     if not Assigned(lParentNode) then exit; 
    // code that uses lParentNode. 
    end; 
+0

Parece ser un puntero válido de interfaz que no es nulo, pero cuando se devuelve a un objeto como TXMLNode (aNode), obtienes nil. Y a veces, esto funciona en el momento de la depuración pero no en el código (el código no ve el nil, pero sí el depurador). Peludo. –

+1

La mayoría de las versiones de Delphi no le permiten convertir un puntero de interfaz a un puntero de objeto. Esa es una característica más nueva que solo está disponible en Delphi 2010 o XE, se me olvida qué la introdujo. Antes de eso, la única forma de obtener un puntero de objeto desde un puntero de interfaz es hacer que la interfaz implemente un método que devuelva el auto puntero de la clase implementadora. –

+0

Acabo de enterarme de eso. No estamos haciendo ningún lanzamiento de ese tipo intencionalmente, excepto que estaba buscando en el depurador y descubrí que puedes volver a la clase, si averiguas qué clase es primero, en el evaluador de expresiones del depurador. –

0

Mi sugerencia es asegurarse de que la función ParentNode se llame realmente en Assigned(aNode.ParentNode). Hay algunos casos desagradables en Delphi donde no se llama a un procedimiento/función sin argumentos, sino que se toma como referencia cuando se omite el paréntesis.

Intenta cambiarlo a Assigned(Anode.ParentNode()) (que debería tener el mismo efecto que la sugerencia de François).

+0

No creo que sea esto. –

Cuestiones relacionadas