Delphi объекты, объекты NIL и интерфейсы - PullRequest
6 голосов
/ 09 сентября 2010

Я ищу подсказки о том, как отлаживать сбой в приложении, которое использует оболочки MS XML в Delphi VCL.Я подозреваю, что повреждение памяти или какое-то неясное зло происходит между объектами и интерфейсами, такое как ошибки подсчета ссылок или повреждение кучи.По сути, вопрос заключается в следующем: как отладить такой сбой?

Этот конкретный код интенсивно используется внутри и распространяется на базовые интерфейсы XmlIntf (IXMLNode).ISomethingCustom - это интерфейс, расширяющий IXMLNode.Проблема возникает, когда мы терпим крах где-то в рекурсивной функции, которой передается ISomethingCustom, который также (или поддерживает также, в терминах интерфейса) 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;

Ситуация в том, что aNode также является IXMLNode, иЗначение IXMLNode.ParentNode присваивается (не nil), и все же оно указывает на COM-объект, который мог быть каким-либо образом освобожден, уничтожен или поврежден.Я пытаюсь выяснить, ЧТО происходит, когда указатель интерфейса может показаться действительным, но объект, стоящий за ним, каким-то образом обстрелян

Checking Assigned (aNode.ParentNode) возвращает TRUE, даже если, если вы пытаетесь выполнить приведение в отладчике (только во время выполнения, а не в коде), например:

  1. проверять / оценивать aNode
  2. проверять / оценивать TInterfacedObject (aNode) .ClassName (работает как минимум в Delphi 2010)Теперь в отладчике я вижу, что это NIL.Что может означать, что волшебная функция «приведение интерфейса к объекту», которая появилась в delphi 2010, не работает.

Я полагаю, что пытаюсь отладить проблему, когда кучи повреждены, или COMобъекты повреждены в куче из-за проблемы подсчета ссылок.

Я действительно считаю, что ни у кого не должно быть ситуации, когда интерфейс кажется действительным, но объект под ним был удален.Я действительно хотел бы знать, что делать и что происходит.

Ответы [ 3 ]

9 голосов
/ 09 сентября 2010

Хотя вы не показали его в своем коде , ваши комментарии, похоже, указывают на то, что вы приводите переменную интерфейса к типу класса. Это не разрешено Я описал почему:

Ссылки на интерфейсы и ссылки на объекты не указывают на одно и то же. Поэтому вызов метода для одного, когда компилятор считает, что у вас есть другой, приведет к неожиданным результатам. Вам не повезло, потому что код продолжал работать, а не падать с нарушением прав доступа, что было бы большим свидетельством того, что вы что-то делали неправильно.

Моя вышеприведенная статья завершается предложением использовать функцию JclSysUtils​.GetImplementorOfInterface из JCL , если у вас есть интерфейс, реализованный на Delphi, и у интерфейса нет собственной функции для выявления базового объекта.

0 голосов
/ 10 сентября 2010

Я предлагаю убедиться, что функция ParentNode действительно вызывается в Assigned(aNode.ParentNode). В Delphi есть несколько неприятных угловых случаев, когда процедура / функция без аргументов не вызывается, а ссылка на нее берется, когда вы опускаете скобки.

Попробуйте изменить его на Assigned(Anode.ParentNode()) (что должно иметь тот же эффект, что и предложение Франсуа).

0 голосов
/ 09 сентября 2010

Дикая догадка: пытались ли вы поместить aNode.ParentNode в локальную переменную и использовать его в остальной части функции Utility:

   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;
...