2010-09-09 4 views
6

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

Этот конкретный код делает интенсивное внутреннее использование и распространяется на базовые интерфейсы 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; 

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

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

  1. осмотр/оценить анодные
  2. инспектировать/оценить TInterfacedObject (анод) .ClassName (работает в Delphi 2010, по крайней мере!)
  3. бросить теперь TWhateverClassNameYouGotBefore (анод).
  4. В отладчике теперь я вижу, что это NIL. Который может означать, что волшебный «интерфейс литья назад к функция объекта, которая является новой в delphi 2010, терпит неудачу.

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

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

+0

Проверка присвоенного (aNode.ParentNode) возвращает TRUE, даже если TNode (aNode) .ParentNode - фактически NIL. <- Вы возвращаете интерфейс обратно к ссылке на объект? –

+0

Должно быть, что-то сломалось. Не намеренно делать кастинг, пока ПОСЛЕ того, что я не заметил, что что-то сломано, я делаю отбрасывания в выражении-оценке в отладчике, просто чтобы увидеть, могу ли я увидеть что-нибудь о том, что находится за интерфейсом. :-) –

ответ

9

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

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

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

+1

Тип-перевод указателя интерфейса обратно на его указатель класса реализации - это новая функция в Delphi 2010 или XE, я забыл, какой из них ее представил. –

+0

Я только возвращался к объекту, потому что заметил, что такое приведение привело к значению NIL и обнаружило, что это любопытно. AT runtime, я фактически не делаю такого актера, кроме как код отладки, который я быстро удалил после обнаружения того, что вы говорите. Он по-прежнему падает, что означает, что у меня есть куча коррупции или что-то еще не так. –

+0

Я полностью переписал свой вопрос, я надеюсь, что это делает природу моей ситуации более ясной. Ваши «указатели» выше сделали мне что-то ясное, чего я раньше не понимал, и это здорово. Учитывая мое полное недоразумение в этой ситуации, я задаюсь вопросом, может ли этот вопрос быть спасен, или если я должен переписать его снова, когда я знаю, что происходит дальше. –

0

Wild догадка: Вы пробовали поставить aNode.ParentNode в локальной переменной и использовать его в остальной части 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

Он представляется действительным указателем интерфейса, отличным от нуля, но при возврате к объекту, подобному TXMLNode (aNode), вы получаете нуль. И иногда это работает во время отладки, но не в коде (код не видит нуль, но отладчик делает это). Волосатые. –

+1

Большинство версий Delphi не позволяют вам вводить указатель интерфейса обратно указателю на объект. Это новая функция, доступная только в Delphi 2010 или XE, я забыл, кто ее представил. До этого единственный способ получить указатель объекта от указателя интерфейса - реализовать интерфейс, реализующий метод, который возвращает указатель Self-класса реализации. –

+0

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

0

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

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

+0

Я не думаю, что это он. –

Смежные вопросы