2009-11-30 10 views
7

Mam aplikację C++ na wielu platformach, która jest podzielona na kilka bibliotek współdzielonych i ładuje dodatkową funkcjonalność z bibliotek współdzielonych wtyczek. Biblioteki wtyczek mają być samodzielne i funkcjonować samodzielnie, bez znajomości lub zależności od aplikacji wywołującej.Segfault w bibliotece wtyczek C++ z podwójnymi symbolami

Jedna z wtyczek zawiera skopiowany kod z głównej aplikacji, więc zawiera nazwy symboli, które są duplikatem tych w silniku. (Tak, wiem, że na ogół nie jest to możliwe, ale w chwili pisania wtyczki silnik był monolitycznym plikiem binarnym i nie mógł udostępniać bibliotek.) W systemie Windows wszystko działa poprawnie. W Linuksie dostaliśmy segfaults. Patrząc na ślad stosu błędu, wystąpił on w wtyczce podczas wywoływania funkcji w zduplikowanej nazwie klasy. Wygląda na to, że jest wynikiem silnika i wtyczki posiadającej nieco inne wersje wspólnego kodu (niektóre funkcje klasy zostały skomentowane w wtyczce). Wyglądało to tak, jakby wtyczka pobierała swoje środowisko uruchomieniowe symboli do silnika zamiast własnego. "Naprawiliśmy" problem, zmieniając parametry dlopen na dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

Ale kiedy przepisaliśmy silnik, aby został podzielony na współdzielone biblioteki (w celu ewentualnego ponownego użycia w wtyczkach), otrzymamy ponownie błąd segfault. I patrząc na ślad stosu, wychodzi z silnika -> plugin -> engine.

Czy istnieje sposób, aby dla łącznika środowiska wykonawczego nie mapować symboli wtyczki do silnika (szczególnie jeśli są zdefiniowane w wtyczce)?

Dzięki! Matt


Edited 2009-12-3

raz pierwszy próbował owinąć kod wtyczki w jego własnej przestrzeni nazw. To nie zadziałało, ponieważ jest statycznie połączone z biblioteką, która jest również połączona z silnikiem. Wersje biblioteki statycznej są różne, więc segfault!

Następnie zmieniłem kompilację silnika i jego bibliotek, aby były statycznie połączone. A kiedy go uruchomię, nie mam już problemu. Wygląda więc na to, że był on eksportowany, a następnie dynamicznie przenoszony do wtyczki podczas jej otwierania. Ale gdy cały kod silnika znajduje się w jednym pliku wykonywalnym, nie eksportuje swoich symboli (więc nie próbuje przenosić symboli wtyczki do silnika).

Nadal mam problem, ponieważ istnieje równoległa wersja programu (z wykorzystaniem Open-MPI), która nadal otrzymuje błąd segfault. Wygląda na to, że wciąż eksportuje symbole silnika i przenosi wtyczki. To może mieć związek z tym, jak Open-MPI wykonuje aplikację.

Czy istnieją flagi linkerów, które mogą być używane w bibliotece współdzielonej wtyczek, które powiedziałyby jej, aby nie zmieniała dynamicznie symboli w środowisku wykonawczym? A może ukryć symbole, żeby się nie przenosiły? Próbowałem już -s ("Pomiń wszystkie informacje o symbolu"), ale to najwyraźniej nie zmieniło symboli dynamicznych (zaznaczone przy użyciu nm -D <plugin>).

+0

Czy są to symbole globalne lub nazwy funkcji? Czy możesz wprowadzić drobne zmiany w kodzie? –

+0

Są to zajęcia i ich funkcje członkowskie. W bazie kodu silnika znajduje się 36 plików, więc nie chcę modyfikować nazw ani plików klas. Chociaż ostatecznym celem jest przepisanie wtyczki, ze względu na ograniczenia czasowe i sprawdzanie poprawności kodu, nie chcę, jeśli nie muszę. – CuppM

+0

@CuppM, więc na przykład masz klasę "Foo" z członkiem "bar" zdefiniowanym w 2 miejscach? A "Foo" ma w obu przypadkach taką samą przestrzeń nazw? Jeśli tak, to nigdy nie będzie działać prawidłowo. Przenieś jeden z "Foo" do jego własnej przestrzeni nazw i życie będzie łatwiejsze. – Glen

Odpowiedz

4

Myślę, że znalazłem rozwiązanie, flaga linkera -Bsymbolic. Zasadniczo ta flaga dodaje flagę do współużytkowanej biblioteki, aby powiadomić linker środowiska wykonawczego, aby najpierw spróbował rozwiązać nazwy symboli w sobie. Silnik był w stanie uruchomić z wtyczką dobrze we wszystkich przypadkach (monolityczne exe, exe w/shared libs, plugin w/i bez pakowania przestrzeni nazw), gdy wtyczka została połączona z tą flagą.

Nie wydaje się być kilka krytycy z ostrzeżeniami o -Bsymbolic:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

Ale biorąc pod uwagę ich ostrzeżeń i co intencją Plugin jest, myślę, że to właściwa opcja dla mnie. Przynajmniej na razie.

1

Zgadzam się z Glenem - tak naprawdę nie rozwiążemy tego, chyba że zmodyfikujecie nazwy klas, prawdopodobnie poprzez przestrzenie nazw. Nawet 36 plików będzie prawdopodobnie potrzebowało mniej czasu na modyfikację, niż próba niezawodnie go naprawić bez zmiany nazw symboli.

Zacznij od zidentyfikowania wszystkich klas, których nazwy wymagają poprawienia. Twój linker prawdopodobnie już je dla Ciebie wymienia. Potem zmieniłbym nazwy zbiorów zarówno zestawów klas (od Foo na Engine :: Foo i Plugin :: Foo na przykład) przynajmniej tymczasowo.W ten sposób można uzyskać kompilator, aby znaleźć wszystkie odniesienia do problematycznych klas. Chug away na źródło wtyczki, dopóki wtyczka nie skompiluje się z odniesieniami do poprawnych nowych nazw klas wtyczek. Gdy to zrobisz, zmień klasy Engine :: Powrót na ich stare nazwy (chyba że chcesz trwale zmodyfikować źródło silnika, co brzmi jak nie). Wtyczka powinna teraz skompilować i połączyć się z prawidłowymi, unikalnie nazwanymi klasami.

+0

Chociaż prawdopodobnie masz rację. Nie jest to jednak satysfakcjonująca odpowiedź, więc na wszelki wypadek pozostawiam pytanie bez odpowiedzi. Zmodyfikuję kod wtyczki, aby dodać przestrzeń nazw do błędnych bitów. Dopóki nie będę mógł go przepisać przy użyciu bibliotek współdzielonych silnika, ponieważ zmieniłem cały kod w silniku, nie powinno to mieć znaczenia, czy zmienię kopię. – CuppM

0

Właśnie zapakowałbym WSZYSTKIE kod wtyczki w przestrzeni nazw PluginX. To na pewno ochroni Cię przed tymi błędami. To bardzo dobra, ważna praktyka.

Powiązane problemy