Segmentation fault using shared library
Habe ich eine shared library (nämlich libXXX.so) mit einem cpp/h-Datei zugeordnet ist.
Sie enthält eine Reihe von Funktionszeigern ( zu zeigen .so entrypoint-Funktion) und eine Klasse zum wrap diese Funktionen als Methoden der Klasse sagte.
dh: .h-Datei:
typedef void* handle;
/* wrapper functions */
handle okUsbFrontPanel_Construct();
void okUsbFrontPanel_Destruct(handle hnd);
/* wrapper class */
class okCUsbFrontPanel
{
public:
handle h;
public:
okCUsbFrontPanel();
~okCUsbFrontPanel();
};
.cpp-Datei, die
/* class methods */
okCUsbFrontPanel::okCUsbFrontPanel()
{ h=okUsbFrontPanel_Construct(); }
okCUsbFrontPanel::~okCUsbFrontPanel()
{ okUsbFrontPanel_Destruct(h); }
/* function pointers */
typedef handle (*OKUSBFRONTPANEL_CONSTRUCT_FN) (void);
typedef void (*OKUSBFRONTPANEL_DESTRUCT_FN) (handle);
OKUSBFRONTPANEL_CONSTRUCT_FN _okUsbFrontPanel_Construct = NULL;
OKUSBFRONTPANEL_DESTRUCT_FN _okUsbFrontPanel_Destruct = NULL;
/* load lib function */
Bool LoadLib(char *libname){
void *hLib = dlopen(libname, RTLD_NOW);
if(hLib){
_okUsbFrontPanel_Construct = ( OKUSBFRONTPANEL_CONSTRUCT_FN ) dlsym(hLib, "okUsbFrontPanel_Construct");
_okUsbFrontPanel_Destruct = ( OKUSBFRONTPANEL_DESTRUCT_FN ) dlsym( hLib, "okUsbFrontPanel_Destruct" );
}
}
/* construct function */
handle okUsbFrontPanel_Construct(){
if (_okUsbFrontPanel_Construct){
handle h = (*_okUsbFrontPanel_Construct)(); //calls function pointer
return h;
}
return(NULL);
}
void okUsbFrontPanel_Destruct(handle hnd)
{
if (_okUsbFrontPanel_Destruct)
(*_okUsbFrontPanel_Destruct)(hnd);
}
Dann habe ich noch eine shared library (von mir), die fordert:
LoadLib("libXXX.so");
okCusbFrontPanel *device = new okCusbFrontPanel();
was in einem Segmentation fault.
Der segmentation fault scheint zu passieren, bei
handle h = (*_okUsbFrontPanel_Construct)();
aber mit einem seltsamen Verhalten: sobald ich erreichen
(*_okUsbFrontPanel_Construct)();
Bekomme ich eine Rekursion zu okUsbFrontPanel_Construct().
Hat jemand eine Idee?
EDIT: hier ist ein backtrace erhalten, indem eine Ausführung mit gdb.
#0 0x007590b0 in _IO_new_do_write () from /lib/tls/libc.so.6
#1 0x00759bb8 in _IO_new_file_overflow () from /lib/tls/libc.so.6
#2 0x0075a83d in _IO_new_file_xsputn () from /lib/tls/libc.so.6
#3 0x00736db7 in vfprintf () from /lib/tls/libc.so.6
#4 0x0073ecd0 in printf () from /lib/tls/libc.so.6
#5 0x02cb68ca in okCUsbFrontPanel (this=0x9d0ae28) at okFrontPanelDLL.cpp:167
#6 0x03cac343 in okUsbFrontPanel_Construct () from /opt/atlas/tdaq/tdaq-02-00-00/installed/i686-slc4-gcc34-dbg/lib/libokFrontPanel.so
#7 0x02cb8f36 in okUsbFrontPanel_Construct () at okFrontPanelDLL.cpp:1107
#8 0x02cb68db in okCUsbFrontPanel (this=0x9d0ade8) at okFrontPanelDLL.cpp:169
#9 0x03cac343 in okUsbFrontPanel_Construct () from /opt/atlas/tdaq/tdaq-02-00-00/installed/i686-slc4-gcc34-dbg/lib/libokFrontPanel.so
#10 0x02cb8f36 in okUsbFrontPanel_Construct () at okFrontPanelDLL.cpp:1107
#11 0x02cb68db in okCUsbFrontPanel (this=0x9d0ada8) at okFrontPanelDLL.cpp:169
#12 0x03cac343 in okUsbFrontPanel_Construct () from /opt/atlas/tdaq/tdaq-02-00-00/installed/i686-slc4-gcc34-dbg/lib/libokFrontPanel.so
#13 0x02cb8f36 in okUsbFrontPanel_Construct () at okFrontPanelDLL.cpp:1107
und so weiter...
IMHO bekomme ich einen seg fault, weil der eine Art von stack overflow. Es gibt zu viele rekursive Aufruf und etwas schief geht..
Durch die Art und Weise ich bin auf einem Scientific Linux 4-Distribution (basierend auf RH4).
EDIT2:
einer objdump von libokFrontPanel.also für die Funktion okUsbFrontPanel_Construct Ausgänge:
00009316 <okUsbFrontPanel_Construct>:
9316: 55 push ebp
9317: 89 e5 mov ebp,esp
9319: 56 push esi
931a: 53 push ebx
931b: 83 ec 30 sub esp,0x30
931e: e8 44 f4 ff ff call 8767 <__i686.get_pc_thunk.bx>
9323: 81 c3 dd bd 00 00 add ebx,0xbddd
9329: c7 04 24 38 00 00 00 mov DWORD PTR [esp],0x38
9330: e8 93 ec ff ff call 7fc8 <_Znwj@plt>
9335: 89 45 e4 mov DWORD PTR [ebp-28],eax
9338: 8b 45 e4 mov eax,DWORD PTR [ebp-28]
933b: 89 04 24 mov DWORD PTR [esp],eax
933e: e8 65 ed ff ff call 80a8 <_ZN16okCUsbFrontPanelC1Ev@plt>
9343: 8b 45 e4 mov eax,DWORD PTR [ebp-28]
9346: 89 45 f4 mov DWORD PTR [ebp-12],eax
9349: 8b 45 f4 mov eax,DWORD PTR [ebp-12]
934c: 89 45 e0 mov DWORD PTR [ebp-32],eax
934f: eb 1f jmp 9370 <okUsbFrontPanel_Construct+0x5a>
9351: 89 45 dc mov DWORD PTR [ebp-36],eax
9354: 8b 75 dc mov esi,DWORD PTR [ebp-36]
9357: 8b 45 e4 mov eax,DWORD PTR [ebp-28]
935a: 89 04 24 mov DWORD PTR [esp],eax
935d: e8 d6 f2 ff ff call 8638 <_ZdlPv@plt>
9362: 89 75 dc mov DWORD PTR [ebp-36],esi
9365: 8b 45 dc mov eax,DWORD PTR [ebp-36]
9368: 89 04 24 mov DWORD PTR [esp],eax
936b: e8 a8 f0 ff ff call 8418 <_Unwind_Resume@plt>
9370: 8b 45 e0 mov eax,DWORD PTR [ebp-32]
9373: 83 c4 30 add esp,0x30
9376: 5b pop ebx
9377: 5e pop esi
9378: 5d pop ebp
9379: c3 ret
in 933e es ist in der Tat ein Aufruf von <_ZN16okCUsbFrontPanelC1Ev@plt>.Ist dieser Aufruf, die verwechselt wird mit der eines in meinem .cpp?
- Sind XXX im code eindeutig?
- ja XXX sind einzigartig.
- Ihre Frage wird verwirrender, je öfter ich es nochmals gelesen. Sind die beiden oben genannten Quellen Teil von libXXX.so, oder ein Teil der "anderen" shared library (von mir)"? Wenn die ehemaligen, dann die Antwort liegt auf der Hand.
- die beiden Quellen sind nicht Teil der libXXX.so . Sie sind Teil des andere gemeinsam genutzte Bibliothek.
- Auf welcher Plattform sind Sie auf? Deine Beschreibung impliziert eine gebrochene dlsym(), aber das ist schwer zu glauben. Ich schlage vor, Sie machen einen reduzierten Testfall demonstriert das gleiche problem, und Editiere deine Frage, um genau zu zeigen, was der code ist, wie es zusammengestellt ist, und was Sie beobachten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nun, dass du gepostet hast
GDB
Ausgabe, es ist klar, was genau dein problem ist.Definieren Sie die gleichen Symbole in
libokFrontPanel.so
und in derlibLoadLibrary.so
(for Lack of a better name -- es ist so viel einfacher, Dinge zu erklären, wenn Sie den richtigen Namen), und , dass verursacht, die eine unendliche Rekursion.Standardmäßig auf UNIX (im Gegensatz zu Windows) alle globalen Symbole aus aller shared-libraries (und das Hauptprogramm) gehen Sie in der single "loader symbol name space".
Unter anderem bedeutet dies, dass, wenn Sie definieren
malloc
im Hauptprogramm, , dassmalloc
genannt werden, die von allen gemeinsam genutzte Bibliotheken, einschließlichlibc
(obwohllibc
hat seine eigenemalloc
definition).So, hier ist was passiert: in
libLoadLibrary.so
Sie definiertokCUsbFrontPanel
Konstruktor. Ich behaupten, dass es auch eine definition, die genaue symbol inlibokFrontPanel.so
. Alle Aufrufe dieses Konstruktors (standardmäßig) gehen Sie auf die erste definition (die, die den dynamischen loader zuerst beobachtet), obwohl die SchöpferlibokFrontPanel.so
habe nicht die Absicht, für diese zu passieren. Die Schleife (in der gleichen ReihenfolgeGDB
gedruckt -- innersten frame oben):Den Aufruf Konstruktor von
#3
war die Absicht zu gehen, um das Zeichen #4 --okCUsbFrontPanel
Konstruktor innenlibokFrontPanel.so
. Stattdessen ging er zu zuvor gesehen definition innerhalblibLoadLibrary.so
: Sie "verdrängt" - symbol #4, und so bildeten eine unendliche Rekursion Schleife.Moral: definieren Sie nicht die gleichen Symbole, die in mehreren Bibliotheken, es sei denn, Sie verstehen die Regeln, nach denen die runtime-loader entscheidet darüber, welche symbol-Referenzen sind gebunden an die Definitionen.
EDIT: Zu beantworten, 'EDIT2' der Frage:
Ja, der Aufruf
_ZN16okCUsbFrontPanelC1Ev
ausokUsbFrontPanel_Construct
wird die definition der Methode in IhremokFrontPanelDLL.cpp
.Es könnte erhellend sein, zu untersuchen
objdump -d okFrontPanelDLL.o
Im Gegensatz zu dem, was Norman Ramsey sagt, ein Werkzeug der Wahl für die Diagnose von segfaults ist
GDB
, nichtvalgrind
.Letzteres ist nur sinnvoll für bestimmte Arten von segfaults (meistens sind diese bezüglich heap-Beschädigung; das scheint nicht der Fall zu sein).
Meine Kristallkugel sagt, dass Ihr
dlopen()
ausfällt (die man ausdrucken solltedlerror()
ob/Wann das passiert!), und dass Ihre_okUsbFrontPanel_Construct
bleibtNULL
. InGDB
Sie werden sofort in der Lage zu sagen, ob diese Schätzung richtig ist.Meine Vermutung widerspricht Ihre Aussage, dass Sie "erhalten eine Rekursion zu okUsbFrontPanel_Construct()". Aber wie können Sie wissen, dass Sie diese Rekursion, wenn Sie nicht sehen mit
GDB
?Das Werkzeug der Wahl für die Diagnose von segfaults ist valgrind. Wenn Sie missbräuchlich Zeiger oder Speicher valgrind finden das problem und geben Sie einen stack-trace auch vor der segfault Auftritt. Auf der FAQ, valgrind Ansprüche zu handhaben shared libraries OK, solange Sie nicht nennen
dlclose()
.Wenn Sie noch nie verwendet, bevor valgrind ich denke, Sie werden erstaunt sein, wie einfach und mächtig er ist. Verwenden Sie einfach 'valgrind' als das erste Wort der Kommandozeile, und Sie findet Ihre Speicher-Fehler. Tolle Sachen! Es gibt eine kurzes Beispiel-Sitzung auf Vladislav Vyshemirsky blog.