Reputation: 774
In the following code, I'm seeing a segfault at the line that says signaling_thread_->Send(this, id, data);
, which is being called from the destructor of the PeerConnectionProxy class.
bool PeerConnectionProxy::Send(uint32 id, talk_base::MessageData* data) {
if (!signaling_thread_)
return false;
signaling_thread_->Send(this, id, data);
return true;
}
Running in gdb, I get the segfault and this stack trace as soon as I do (gdb) step
to that line:
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
...
Breaking just before that line, I check that, as expected, signaling_thread_ is non-null, as is this and data. I'm just quite confused as to what could be causing a segfault there or making the stack end up at 0x00000000. The code only segfaults on the code path through the destructor. The Send function is called from numerous other places with no problem.
Update 2011-12-08:
Stepping through with stepi and disassembly turned on, I get this:
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
ecx
is 0x0 so that's what's making it segfault but I still don't understand what's going on. The other code for the line doesn't look to touch ecx
, unless I'm just reading it wrong.
Upvotes: 3
Views: 1736
Reputation: 49118
%ecx
holds the virtual table entry for the Send
method, which has been zeroed out for some reason. Most commonly with a destructor is that signaling_thread_
is being deleted before the call to PeerConnectionProxy::Send
. Another possibility is a buffer overrun in a previous call to a signaling_thread_
method, which is overwriting the virtual table entry. Another possibility is a buffer overrun in the destructor that's overwriting the signaling_thread_
pointer. If you post the code to your destructor we might be able to narrow it down.
Upvotes: 1
Reputation: 126418
Most likely cause is that signaling_thread_
is a dangling pointer -- it used to point at something, but that something has been delete
'd, leaving a pointer that isn't null, but will likely cause a crash if you try to do anything with it (such as calling the Send
method on it).
Since you say this is being called from the destructor, its quite possible that the delete call occured earlier in the same destructor...
Upvotes: 3
Reputation: 27153
Whenever I have a segfault that involves destructors, it is often solved by making the destructors virtual
. Don't worry if this doesn't make sense to you yet.
When an object is to be destroyed, first the destructor will be called, then an attempt will be made to free the object. Often, the destructor itself is entirely successful, but the attempt to free memory fails due to an obscure issue which I will attempt to describe later. (This answer references the relevant part of the C++ standard.)
Are you sure that the segfault happens during the destructor? Or perhaps it happens immediately after the destructor completes. Can you put in a printf at the end of the relevant destructor, please?
I'm going to assume that the destructor function itself is successful and that the error happens immediately after the destructor, during the attempt to free the memory.
consider this struct:
struct A {
int x;
};
A a;
Here, clearly &a == &(a.x)
And B inherits from A:
struct B : public A {
};
B b;
Again, &b == &(b.x)
But if virtual methods are involved, things get tricky.
struct C : public B {
virtual void foo() {}
};
C c;
Now, &c != &(c.x)
. This is because the first true entry of c
is (compiler-dependant) actually a vtable which lists the location of functions such as foo(). Now imagine the following code:
{
A * p = new C;
delete p;
}
The statement delete p
thinks it is dealing with an object of type A
, but it's actually dealing with an object of type C
. The destructor will operate correctly, but the attempt to call free(p)
will be wrong because it's not using the correct address. It's like int *p = malloc(100); free(p+1)
.
If in doubt, put a virtual
destructor in every class if you might ever inherit from it with virtual functions in the subclass.
Upvotes: 1