C++ 是什么导致此代码出现故障

C++ 是什么导致此代码出现故障,c++,segmentation-fault,destructor,C++,Segmentation Fault,Destructor,在下面的代码中,我看到一个segfault出现在写有signaling\u thread\u->Send(这个,id,data)的行中,从PeerConnectionProxy类的析构函数调用 bool PeerConnectionProxy::Send(uint32 id, talk_base::MessageData* data) { if (!signaling_thread_) return false; signaling_thread_->Send(this,

在下面的代码中,我看到一个segfault出现在写有
signaling\u thread\u->Send(这个,id,data)的行中,从PeerConnectionProxy类的析构函数调用

bool PeerConnectionProxy::Send(uint32 id, talk_base::MessageData* data) {
  if (!signaling_thread_)
    return false;
  signaling_thread_->Send(this, id, data);
  return true;
}
在gdb中运行时,只要我对该行执行
(gdb)步骤
,我就会得到segfault和该堆栈跟踪:

Program received signal SIGSEGV, Segmentation fault.

0x00000000 in ?? ()
(gdb) bt
#0  0x00000000 in ?? ()
#1  0xa782eed4 in webrtc::PeerConnectionProxy::Send (this=0xab889e80, id=6, data=0xbfffc1e8)
    at third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.cc:219
#2  0xa782e91a in ~PeerConnectionProxy (this=0xab889e80, __in_chrg=<value optimised out>)
    at third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.cc:145

...
程序接收信号SIGSEGV,分段故障。
0x00000000英寸??()
(gdb)英国电信
#0 0x00000000英寸??()
#webrtc::PeerConnectionProxy::Send中的1 0xa782eed4(this=0xab889e80,id=6,data=0xbfffc1e8)
第三方/libjingle/source/talk/app/webrtc/peerconnectionproxy.cc:219
#~PeerConnectionProxy中的2 0xa782e91a(this=0xab889e80,\u-in\u-chrg=)
第三方/libjingle/source/talk/app/webrtc/peerconnectionproxy.cc:145
...
在该行之前中断,我检查信令线程是否如预期的那样为非空,这与数据一样。我只是很困惑,到底是什么导致了segfault,还是导致堆栈最终达到0x00000000。代码仅在通过析构函数的代码路径上分段故障。Send函数是从许多其他地方调用的,没有问题

更新2011-12-08:

在打开stepi和Discomblish的情况下,我得到以下结果:

0xa772eed2  219   signaling_thread_->Send(this, id, data);
   0xa772eea4 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+24>:     8b 45 08   mov    0x8(%ebp),%eax
   0xa772eea7 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+27>:     8b 40 0c   mov    0xc(%eax),%eax
   0xa772eeaa <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+30>:     8b 00  mov    (%eax),%eax
   0xa772eeac <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+32>:     83 c0 40   add    $0x40,%eax
   0xa772eeaf <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+35>:     8b 08  mov    (%eax),%ecx
   0xa772eeb1 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+37>:     8b 45 08   mov    0x8(%ebp),%eax
   0xa772eeb4 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+40>:     8d 70 04   lea    0x4(%eax),%esi
   0xa772eeb7 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+43>:     8b 45 08   mov    0x8(%ebp),%eax
   0xa772eeba <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+46>:     8b 40 0c   mov    0xc(%eax),%eax
   0xa772eebd <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+49>:     8b 55 10   mov    0x10(%ebp),%edx
   0xa772eec0 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+52>:     89 54 24 0c    mov    %edx,0xc(%esp)
   0xa772eec4 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+56>:     8b 55 0c   mov    0xc(%ebp),%edx
   0xa772eec7 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+59>:     89 54 24 08    mov    %edx,0x8(%esp)
   0xa772eecb <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+63>:     89 74 24 04    mov    %esi,0x4(%esp)
   0xa772eecf <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+67>:     89 04 24   mov    %eax,(%esp)
=> 0xa772eed2 <_ZN6webrtc19PeerConnectionProxy4SendEjPN9talk_base11MessageDataE+70>:     ff d1  call   *%ecx
0xA772EED219信令线程->发送(此,id,数据);
0xa772eea4:8b 45 08 mov 0x8(%ebp),%eax
0xa772eea7:8b 40 0c mov 0xc(%eax),%eax
0xa772eeaa:8b 00 mov(%eax),%eax
0xa772eeac:83 c0 40添加$0x40,%eax
0xa772eeaf:8b 08 mov(%eax),%ecx
0xa772eeb1:8b 45 08 mov 0x8(%ebp),%eax
0xa772eeb4:8d 70 04 lea 0x4(%eax),%esi
0xa772eeb7:8b 45 08 mov 0x8(%ebp),%eax
0xa772eeba:8b 40 0c mov 0xc(%eax),%eax
0xa772eebd:8b 55 10 mov 0x10(%ebp),%edx
0xa772eec0:89 54 24 0c mov%edx,0xc(%esp)
0xa772eec4:8b 55 0c mov 0xc(%ebp),%edx
0xa772eec7:89 54 24 08 mov%edx,0x8(%esp)
0xa772eecb:89 74 24 04 mov%esi,0x4(%esp)
0xa772eecf:89 04 24 mov%eax,(%esp)
=>0xa772eed2:ff d1调用*%ecx

ecx
是0x0,所以这就是它的原因,但我仍然不明白发生了什么。该行的另一个代码看起来不会触及ecx,除非我只是读错了。

每当我遇到涉及析构函数的segfault时,通常通过使析构函数虚拟来解决。如果这对你来说还没有意义,不要担心

当要销毁对象时,首先调用析构函数,然后尝试释放该对象。通常,析构函数本身是完全成功的,但是释放内存的尝试失败了,因为有一个模糊的问题,我将在后面尝试描述。(引用C++标准的相关部分)

你确定segfault发生在析构函数期间吗?或者它可能在析构函数完成后立即发生。你能在相关析构函数的末尾加一个printf吗

我将假设析构函数本身是成功的,并且错误发生在析构函数之后,在尝试释放内存的过程中

考虑这个结构:

struct A {
    int x;
};
A a;
这里,显然
&a==&(a.x)

B继承自A:

struct B : public A {
};
B b;
同样,
&b==&(b.x)

但如果涉及虚拟方法,事情就会变得棘手

struct C : public B {
   virtual void foo() {}
};
C c;
现在,
&c!=&(c.x)
。这是因为
c
的第一个真正条目实际上是(依赖于编译器)一个vtable,它列出了函数的位置,例如foo()。现在想象一下下面的代码:

{
    A * p = new C;
    delete p;
}
语句
delete p
认为它正在处理
A
类型的对象,但实际上它正在处理
C
类型的对象。析构函数将正常运行,但调用
free(p)
的尝试将是错误的,因为它没有使用正确的地址。就像
int*p=malloc(100);免费(p+1)


如果有疑问,在每个类中放置一个
virtual
析构函数,如果您可能在子类中使用虚拟函数继承它。

最可能的原因是
信令线程是一个悬空指针——它用来指向某个对象,但某个对象已被
删除,留下一个非空指针,但是,如果您尝试对其执行任何操作(例如对其调用
Send
方法),则可能会导致崩溃


因为您说这是从析构函数调用的,所以很可能是同一析构函数中较早发生的删除调用…

%ecx
保存了
Send
方法的虚拟表项,由于某种原因,它已被调零。最常见的析构函数是在调用
PeerConnectionProxy::Send
之前删除
信令线程。另一种可能是在先前调用
signaling\u thread\u
方法时发生缓冲区溢出,该方法正在覆盖虚拟表项。另一种可能是析构函数中的缓冲区溢出,它覆盖了
信令\u线程\u
指针。如果您将代码发布到析构函数,我们可能会缩小它的范围。

看起来可能是堆栈损坏。我建议您在Valgrind下重新运行。您是否可以通过
stepi
而不是
step
获得更多信息?更新了stepi的结果。我仍在尝试让应用程序运行在ValGReND中。C++对象的一部分(在很多情况下)是一个虚拟表,用于处理<代码>虚拟< /C>方法。很可能,你的已经被腐蚀了,valgrind也许能帮上忙。除此之外,您可以使用gdb中的数据访问断点来查找它何时被损坏。我想我现在已经找到了它。我正在编写的代码混合了boost::shared_ptr和原始指针(这似乎是一个非常糟糕的主意)。信号灯