2010-09-09 15 views
6

Szukam wskazówek, jak debugować awarię w aplikacji, która używa obwolut XML XML w Delphi VCL. Podejrzewam, że zepsuło się pamięć lub jakieś niejasne zło dzieje się między obiektami i interfejsami, takie jak błędy liczące odniesienia lub korupcja sterty. Pytanie brzmi: w jaki sposób mogę debugować taką awarię?Obiekty Delphi, obiekty NIL i interfejsy

Ten konkretny kod intensywnie wykorzystuje wewnętrzne interfejsy XmlIntf (IXMLNode) i rozszerza je. ISomethingCustom to interfejs, który rozszerza IXMLNode. Problem pojawia się tam, gdzie zawieszamy się gdzieś w funkcji rekurencyjnej, która jest przekazywana przez ISomethingCustom, który jest również (lub obsługuje również, w kategoriach interfejsu) 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; 

Sytuacja jest taka, że ​​anoda jest również IXMLNode, a wartość IXMLNode.ParentNode jest przypisany (nie zero), a mimo to wskazuje na obiekt COM, które mogły zostać uwolniony, zniszczony lub uszkodzony w jakiś sposób. Próbuję dowiedzieć się, CO dzieje się, gdy wskaźnik interfejsu może wydawać się poprawny, ale obiekt za nim został nuked jakoś.

Sprawdzanie określony cel (aNode.ParentNode) zwraca TRUE, nawet jeśli były do ​​próby oddanych w debugger (tylko w czasie wykonywania, a nie w kodzie), podobnie jak to:

  1. skontrolować/oceny anoda
  2. sprawdzić/ocenić TInterfacedObject (anoda) .nazwaklasy (prac w Delphi 2010, co najmniej!)
  3. teraz rzucać TWhateverClassNameYouGotBefore (anoda).
  4. W debugerze widzę teraz, że jest to NIL. Co może oznaczać, że magiczny "interfejs rzutowania z powrotem do obiektu" cecha, która jest nowa w delphi 2010, nie działa.

Wierzę, że próbuję debugować problem, w którym hałdy są uszkodzone, lub obiekty COM są uszkodzone na stercie, z powodu problemu z licznikiem odniesień.

Naprawdę myślę, że nikt nigdy nie powinien mieć sytuacji, w której interfejs wydaje się prawidłowy, ale obiekt pod spodem został usunięty. Naprawdę chciałbym wiedzieć, co robić i co się dzieje.

+0

Sprawdzanie przypisane (aNode.ParentNode) zwraca TRUE, nawet jeśli TNode (aNode) .ParentNode jest faktycznie NIL. <- Czy przesyłasz interfejs do odwołania do obiektu? –

+0

Musimy robić coś zepsutego. Nie celowo wykonuję castingu, dopóki PO Zauważeniu, że coś nie jest zepsute, wykonuję rzuty w wyrażeniu-wyrażeniu w debugerze, tylko po to, aby zobaczyć, czy widzę coś, co kryje się za interfejsem. :-) –

Odpowiedz

9

Chociaż nie wykazano go w kodzie, twój komentarze wydają się wskazywać, że odrzucasz zmienną interfejsu do typu klasy. To nie jest dozwolone. Opisałem dlaczego:

referencje interfejsu i obiekt odniesienia nie wskazują na te same rzeczy. Dlatego wywołanie metody na jednym, gdy kompilator myśli, że masz drugą, przyniesie nieoczekiwane wyniki. Miałeś pecha, ponieważ kod nadal działał, zamiast awaryjnie naruszać prawa dostępu, co oznaczałoby, że robiłeś coś złego.

Powyższy artykuł kończy się sugerowaniem, że używasz funkcji JclSysUtils​.GetImplementorOfInterface z JCL, jeśli masz interfejs implementowany przez Delphi i interfejs nie oferuje własnej funkcji do ujawnienia obiektu leżącego pod spodem.

+1

Przekazywanie wskaźnika interfejsu z powrotem do wskaźnika klasy implementacji to nowa funkcja w Delphi 2010 lub XE, nie pamiętam, który z nich został wprowadzony. –

+0

Odsunąłem się tylko do Obiektu, ponieważ zauważyłem, że taka obsada przyniosła wartość NIL i okazało się to interesujące. W środowisku wykonawczym AT tak naprawdę nie wykonuję takiej obsady, z wyjątkiem kodu debugowania, który szybko usunąłem po odkryciu tego, co mówisz. Nadal się zawiesza, co oznacza, że ​​albo mam korupcję, albo coś, co idzie nie tak. –

+0

Prawie całkowicie przerobiłem moje pytanie, mam nadzieję, że uwypukli to charakter mojej sytuacji. Twoje "wskaźniki" powyżej uświadomiły mi coś, czego wcześniej nie rozumiałem, co jest świetne. Biorąc pod uwagę moje całkowite niezrozumienie sytuacji, zastanawiam się, czy to pytanie można uratować, czy też powinienem je ponownie napisać, gdy będę wiedział, co się dzieje. –

0

Dzikie przypuszczenie: Czy próbowali umieścić aNode.ParentNode w zmiennej lokalnej i używać go w pozostałej części 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

Wygląda na to, że jest poprawnym wskaźnikiem interfejsu, który nie jest zerowy, ale po odesłaniu do obiektu takiego jak TXMLNode (aNode), otrzymasz zero. Czasami działa to w czasie debugowania, ale nie w kodzie (kod nie widzi wartości zerowej, ale debugger działa). Włochaty. –

+1

Większość wersji Delphi nie pozwala na wpisanie wskaźnika interfejsu z powrotem do wskaźnika obiektu. Jest to nowsza funkcja dostępna tylko w Delphi 2010 lub XE, zapominam, która wprowadziła go. Wcześniej jedynym sposobem na uzyskanie wskaźnika obiektu ze wskaźnika interfejsu jest zaimplementowanie w interfejsie metody zwracającej wskaźnik Self klasy implementującej. –

+0

Właśnie się o tym dowiedziałem. Nie celowo robimy takich rzutów poza tym, że rzuciłem okiem w debuggerze i odkryłem, że MOŻESZ odsyłać z powrotem do klasy, jeśli dowiesz się, która klasa jest pierwsza, w oceniającym wyrażenie debuggera. –

0

Moja sugestia polega na upewnieniu się, że funkcja ParentNode jest rzeczywiście wywoływana w Assigned(aNode.ParentNode). W Delphi istnieją pewne nieprzyjemne przypadki narożnikowe, w których procedura/funkcja bez argumentów nie jest wywoływana, ale raczej odwołanie jest brane gdy pominięto nawias.

Spróbuj zmienić na Assigned(Anode.ParentNode()) (który powinien mieć taki sam efekt, jak sugestia François).

+0

Nie sądzę, że to jest to. –