Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi objects, NIL objects and Interfaces

I am looking for hints on how to debugging a crash in an application that uses the MS XML wrappers in the Delphi VCL. I suspect memory corruption, or some kind of obscure evil thing happening between objects and interfaces, such as reference counting bugs, or heap corruption. The question is, in effect: how do I debug such a crash?

This particular code makes heavy internal use of and extends on the base XmlIntf Interfaces (IXMLNode). ISomethingCustom is an interface that extends IXMLNode. THe problem happens where we crash somewhere in a recursive function that is passed an ISomethingCustom which is also (or supports also, in interface terms) 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;

The situation is that the aNode is also IXMLNode, and IXMLNode.ParentNode value is assigned (not nil), and yet it points to a COM object that may have been freed, destroyed, or corrupted somehow. I am trying to figure out WHAT is going on when an interface pointer can appear to be valid, but the object behind it has been nuked somehow.

Checking Assigned(aNode.ParentNode) returns TRUE, even when, if you were to attempt a cast in the debugger (at runtime only, not in the code), like this:

  1. inspect/evaluate aNode
  2. inspect/evaluate TInterfacedObject(aNode).ClassName (works in Delphi 2010, at least!)
  3. now cast TWhateverClassNameYouGotBefore(aNode).
  4. In the debugger I now see that this is NIL. WHich may mean that the magic "casting interface back to the object" feature that is new in delphi 2010, is failing.

I believe I am trying to debug a problem where heaps are corrupted, or COM objects are corrupt on the heap, because of a reference counting problem.

I really think that nobody should ever have the situation arise where an interface appears valid, but the object underneath has been deleted. I really would like to know what to do, and what is going on.

like image 579
Warren P Avatar asked Sep 09 '10 16:09

Warren P


1 Answers

Although you haven't shown it in your code, your comments seem to indicate that you're type-casting the interface variable to a class type. That's not allowed. I've described why:

  • Why can’t I cast an interface reference to an object reference?

Interface references and object references don't point to the same things. Therefore, calling a method on one when the compiler thinks you have the other will yield unexpected results. You were unlucky because the code continued to run instead of crashing with an access violation, which would have been a bigger indication that you were doing something wrong.

My article above concludes by suggesting you use the JclSysUtils​.GetImplementorOfInterface function from the JCL if you have a Delphi-implemented interface and the interface offers no function of its own for revealling the underlying object.

like image 200
Rob Kennedy Avatar answered Sep 18 '22 23:09

Rob Kennedy