2015-12-02 21 views
5

Mam wielowątkową aplikację OS X, która używa mieszaniny C++, Objective-C i Swift.Jak wyśledzić "libC++ abi.dylib: Czysta wirtualna funkcja nazywana!" w Xcode

Kiedy moja aplikacja zostanie zamknięty, widzę to w oknie Xcode debuggera:

libc++abi.dylib: Pure virtual function called! 

wiem, że ten błąd jest zazwyczaj spowodowane przez wywołanie funkcji wirtualnych w C klasy konstruktora lub destruktora ++.

Czy istnieje prosty sposób na znalezienie miejsca? Przez "Easy" mam na myśli "nie analizowanie drzew wywołań dla każdej linii każdego konstruktora i destruktora każdej klasy, która ma funkcję wirtualną".

Nie widzę śladu stosu. Debugger nie zatrzymuje programu po wydrukowaniu tego komunikatu. Komunikat rejestrowany w metodzie delegata mojej aplikacji applicationDidTerminate poprzedza tę wiadomość.

Próbowałem ustawić punkt przerwania na "Wszystkie wyjątki", ale niestety ten punkt przerwania jest często trafiony przez kod, który używa wielu wyjątków. Czy jest jakiś inny symbol, w którym mogę umieścić punkt przerwania?

+0

przyjrzyj się dowolnej klasie, która wywołuje metodę wirtualną w swoim destruktorze, lub wywołuje dowolną metodę w jej destruktorze - ponieważ metody te mogą same wywoływać metody wirtualne. W destruktorze klasy bazowej klasa pochodna już nie istnieje, więc wirtualne wywołania funkcji wykonają wersję klasy podstawowej. –

+0

Zazwyczaj generowany jest raport z dziennika awarii, ponieważ ten błąd jest wyjątkiem "SIGABRT". W przypadku, gdy nie ma wtedy, możesz przeszukać kod dla "wirtualny" i ustawić punkty przerwania na każdym z nich; powinno to być po prostu kwestią procesu eliminacji. –

+1

Ustaw punkt przerwania na '__cxa_pure_virtual' –

Odpowiedz

3

Standardowe biblioteki C++ definiują kilka funkcji "ABI", które implementują funkcje języka/biblioteki niskiego poziomu. libc++ ma ładny dokument, który opisuje je here.

Jednym z nich jest __cxa_pure_virtual, który jest wywoływany, gdy program w jakiś sposób wywołuje funkcję czysto wirtualną. Jeśli więc ustawisz tam punkt przerwania, powinieneś być w stanie dowiedzieć się, gdzie to się dzieje.

Zwykle wywołania funkcji czystych wirtualnych występują, gdy wywołuje się funkcję wirtualną z poziomu konstruktora lub destruktora, podczas gdy vtable znajduje się w stanie pośrednim.Aby uzyskać więcej informacji, patrz this answer.

1

Najpierw jest najczęściej w destruktorze, w którym wywoływane jest wywołanie funkcji czysto wirtualnej, a nie konstruktora (nie jest to gwarantowane, ale prawdopodobnie).

Jeśli kompilator generuje wyjątek, gdy wywoływana jest funkcja czysto wirtualna, być może uda się go przechwycić, ustawiając własny program obsługi zakończeń z set_terminate() (np. Wyjaśniono here). Następnie możesz ustawić punkt przerwania w swoim programie obsługi zakończeń, aby zobaczyć dokładnie, jak twój kod dociera do tego punktu.

Jeśli wyjątek nie zostanie wygenerowany przez kompilator, gdy zostanie wywołana funkcja czysto wirtualna (sytuacja bardziej prawdopodobna), wówczas można spróbować dodać własne fałszywe klasy, aby zawęzić miejsce, w którym występuje wywołanie obraźliwe. Po prostu niech te obojętne klasy drukują coś w swoich destruktorach i upewnij się, że zostaną usunięte w czasie, który pomaga zawęzić, gdy coś się wydarzy. Na przykład umieść go na samym początku funkcji main(), a jeśli zobaczysz jego komunikat, to wywołanie obraźliwe dzieje się, gdy obiekty statyczne są usuwane, ponieważ ten sztuczny obiekt byłby ostatnim obiektem usuniętym przed powrotem funkcji main(). Możesz zrobić podobne rzeczy, dodając takie dummy klasy jako pierwszy element danych innych klas, które możesz modyfikować, ale potrzebujesz pomysłu na usuwanie obiektów prowadzących do szkodliwego czystego wirtualnego wywołania funkcji.

Na koniec, w przypadku, gdy jest to użyteczne, można faktycznie zapewnić implementację czystych funkcji wirtualnych, które można w rzeczywistości nazwać (tak, to jest legalne C++). Jeśli znasz dokładną czystą funkcję wirtualną, która jest wywoływana, możesz podać jej implementację i umieścić tam punkt przerwania, aby przechwycić ślad stosu. Jest to zależne od tego, czy znasz dokładnie czystą wirtualną funkcję, która jest wywoływana, a twoje pytanie sugeruje, że może ona nie być znana.

Powiązane problemy