C++ 利用共享库进行故障分割

C++ 利用共享库进行故障分割,c++,memory-management,shared-libraries,segmentation-fault,C++,Memory Management,Shared Libraries,Segmentation Fault,我有一个共享库(即libXXX.so),其中有一个关联的cpp/h文件。 它们包含许多函数指针(指向.so函数入口点)和一个类,用于将这些函数包装为所述类的方法 ie:.h文件: typedef void* handle; /* wrapper functions */ handle okUsbFrontPanel_Construct(); void okUsbFrontPanel_Destruct(handle hnd); /* wrapper class */ class okCUsbFr

我有一个共享库(即libXXX.so),其中有一个关联的cpp/h文件。 它们包含许多函数指针(指向.so函数入口点)和一个类,用于将这些函数包装为所述类的方法

ie:.h文件:

typedef void* handle;
/* wrapper functions */
handle okUsbFrontPanel_Construct();
void okUsbFrontPanel_Destruct(handle hnd);

/* wrapper class */
class okCUsbFrontPanel
{
public:
  handle h;
public:
  okCUsbFrontPanel();
  ~okCUsbFrontPanel();
};
.cpp文件

/* 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);
}
然后我有另一个共享库(我自己制作),它调用:

LoadLib("libXXX.so");
okCusbFrontPanel *device = new okCusbFrontPanel();
导致分割错误。 分段错误似乎发生在

handle h = (*_okUsbFrontPanel_Construct)();
但有一种奇怪的行为:一旦我到达

(*_okUsbFrontPanel_Construct)(); 
我得到了对okUsbFrontPanel_Construct()的递归

有人知道吗

编辑:这是通过使用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
等等。。。 我怎么会因为堆栈溢出而出现seg故障。递归调用太多,出现了一些问题

顺便说一句,我使用的是一个科学的Linux4发行版(基于RH4)

编辑2:

libokFrontPanel.so的objdump对于函数okUsbFrontPanel_构造输出:

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    
00009316:
9316:55推式ebp
9317:89 e5 mov ebp,esp
9319:56推式esi
931a:53推动ebx
931b:83 ec 30子esp,0x30
931e:e8 44 f4 ff ff呼叫8767
9323:81 c3 dd bd 00 00添加ebx,0xbddd
9329:c7 04 24 38 00 mov DWORD PTR[esp],0x38
9330:e8 93欧共体ff ff呼叫7fc8
9335:89 45 e4 mov DWORD PTR[ebp-28],eax
9338:8b 45 e4 mov eax,德沃德PTR[ebp-28]
933b:89 04 24 mov DWORD PTR[esp],eax
933e:e8 65 ed ff ff呼叫80a8
9343:8b 45 e4 mov eax,德沃德PTR[ebp-28]
9346:89 45 f4 mov DWORD PTR[ebp-12],eax
9349:8b 45 f4 mov eax,德沃德PTR[ebp-12]
934c:89 45 e0 mov DWORD PTR[ebp-32],eax
934f:eb 1f jmp 9370
9351:89 45直流移动DWORD PTR[ebp-36],eax
9354:8b 75 dc mov esi,DWORD PTR[ebp-36]
9357:8b 45 e4 mov eax,德沃德PTR[ebp-28]
935a:89 04 24 mov DWORD PTR[esp],eax
935d:e8 d6 f2 ff ff呼叫8638
9362:89 75 dc mov DWORD PTR[ebp-36],esi
9365:8b 45直流mov eax,德沃德PTR[ebp-36]
9368:89 04 24 mov DWORD PTR[esp],eax
936b:e8 a8 f0 ff ff呼叫8418
9370:8b 45 e0 mov eax,德沃德PTR[ebp-32]
9373:83 c4 30添加esp,0x30
9376:5b波普ebx
9377:5e pop esi
9378:5d pop ebp
9379:c3 ret

在933e确实有一个调用。这个调用是否与my.cpp中的调用混淆了?

诊断SEGFULTS的工具是。如果您误用了指针或内存,valgrind将在segfault发生之前发现问题并提供堆栈跟踪。在常见问题解答中,valgrind声称只要不调用
dlclose()
,就可以处理共享库


如果你以前从未使用过valgrind,我想你会惊讶于它是多么简单和强大。您只需使用“valgrind”作为命令行的第一个字,它就会发现内存错误。好东西!Vladislav Vyshemirsky的博客上有一篇文章。

诊断断层的首选工具是。如果您误用了指针或内存,valgrind将在segfault发生之前发现问题并提供堆栈跟踪。在常见问题解答中,valgrind声称只要不调用
dlclose()
,就可以处理共享库


如果你以前从未使用过valgrind,我想你会惊讶于它是多么简单和强大。您只需使用“valgrind”作为命令行的第一个字,它就会发现内存错误。好东西!Vladislav Vyshemirsky的博客上有一篇文章。

与Norman Ramsey所说的相反,诊断SegFault的首选工具是
GDB
,而不是
valgrind

后者只对某些类型的SegFault有用(大部分与堆损坏有关;这里的情况似乎不是这样)

我的水晶球说你的
dlopen()
失败了(如果发生这种情况,你应该打印
dlerror()
),并且你的
\u okUsbFrontPanel\u构造仍然是
空的
。在
GDB
中,您将能够立即判断该猜测是否正确


我的猜测与您的陈述相矛盾,您的陈述是“得到一个到okUsbFrontPanel_Construct()的递归”。但是如果你不使用
GDB
,你怎么知道你得到了这样的递归呢?

与诺曼·拉姆齐所说的相反,诊断分段故障的首选工具是
GDB
,而不是
valgrind

后者只对某些类型的分段故障有用(大部分与堆损坏有关;这里的情况似乎不是这样)

我的水晶球告诉我,你的
dlopen()
失败了(如果发生这种情况,你应该打印
dlerror()
),你的
\okUsbFrontPanel\u构造仍然是
NULL
。在
GDB
中,你可以立即判断出猜测是否正确


我的猜测与你的陈述相矛盾,你说你“得到了一个对okUsbFrontPanel_Construct()的递归”。但是如果你没有使用
GDB
,你怎么知道你得到了这样的递归呢?

既然你已经发布了
GDB
输出,你的问题就清楚了

您在
libokFrontPanel.so
libLoadLibrary.so
中定义了相同的符号(因为没有更好的名称——正确命名后解释事物会容易得多),这导致了无限递归

默认情况下,在UNIX上(与Windows不同),所有共享库(以及主可执行文件)中的所有全局符号都会消失
 #1 okCUsbFrontPanel () at okFrontPanelDLL.cpp:169
 #3 okUsbFrontPanel_Construct () from libokFrontPanel.so
 #2 okUsbFrontPanel_Construct () at okFrontPanelDLL.cpp:1107
 #1 okCUsbFrontPanel () at okFrontPanelDLL.cpp:169