Bug 14576

Summary: Call cancellation during teardown can crash stream-engine
Product: Telepathy Reporter: Simon McVittie <smcv>
Component: tp-glibAssignee: Telepathy bugs list <telepathy-bugs>
Status: RESOLVED FIXED QA Contact: Telepathy bugs list <telepathy-bugs>
Severity: normal    
Priority: high    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:

Description Simon McVittie 2008-02-20 03:14:20 UTC
If a TpProxyPendingCall holds the only reference to its TpProxy (i.e. it's only being kept alive for the duration of that call), the TpProxy holds the only reference to its DBusGProxy (this is normal), and the TpProxyPendingCall is cancelled (explicitly or by losing a weak ref), then it is possible that the following chain of events will occur:

* TpProxyPendingCall cancels its DBusGProxyPendingCall
* Control enters dbus_g_proxy_cancel_call
* TpProxyPendingCall is completed as a result, and is freed
* TpProxy is unreffed and freed
* DBusGProxy is unreffed and freed
* Control re-enters dbus_g_proxy_cancel_call
* dbus_g_proxy_cancel_call manipulates the DBusGProxy's hash table...
* ... but the DBusGProxy no longer exists
* SIGSEGV

This can happen in stream-engine HEAD when the condition "connection manager gave us a new stream with existing id 1, sending error!" occurs (about 1 call in 6 at the moment).

Arguably, dbus_g_proxy_cancel_call should ref the DBusGProxy for the duration, or re-order its code so it doesn't need to. However, it doesn't, so we should.

The resulting backtrace (with extra debug logging inserted into telepathy-glib and dbus-glib) looks like this:

(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255739: tp_proxy_pending_call_lost_weak_ref: 0x8075598 lost weak ref to 0x812c148
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255755: tp_proxy_pending_call_cancel: 0x8075598
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255770: tp_proxy_pending_call_cancel: Cancelling pending call 0x2 on DBusGProxy 0x80e6b68
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.255787: dbus_g_proxy_cancel_call 0x80e6b68 0x2: enter
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.255802: dbus_g_proxy_cancel_call 0x80e6b68 0x2: cancel 0x81c4c90
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.255820: dbus_g_proxy_cancel_call 0x80e6b68 0x2: remove from hash table
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255836: tp_proxy_pending_call_v0_completed: 0x8075598
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255850: tp_proxy_pending_call_v0_completed: Freeing myself
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255865: tp_proxy_pending_call_free: 0x8075598
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255885: tp_proxy_dispose: 0x81b1830
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255903: tp_proxy_invalidate: 0x81b1830: Proxy unreferenced
(telepathy-stream-engine:15107): tp-glib-DEBUG: 2008-02-20 10:51:35.255947: tp_proxy_finalize: 0x81b1830
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.255973: dbus_g_proxy_dispose: 0x80e6b68
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.255989: dbus_g_proxy_dispose: actually disposing of 0x80e6b68
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.256020: dbus_g_proxy_dispose: chain up (0x80e6b68)
** (telepathy-stream-engine:15107): DEBUG: 2008-02-20 10:51:35.256038: dbus_g_proxy_dispose: leave (0x80e6b68)
[New Thread 0xb481bb90 (LWP 15127)]
[New Thread 0xb401ab90 (LWP 15128)]
[Thread 0xb481bb90 (LWP 15127) exited]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb79176b0 (LWP 15107)]
g_hash_table_resize (hash_table=0x8176fc0)
    at /tmp/buildd/glib2.0-2.14.6/glib/ghash.c:827
827	/tmp/buildd/glib2.0-2.14.6/glib/ghash.c: No such file or directory.
	in /tmp/buildd/glib2.0-2.14.6/glib/ghash.c
#0  g_hash_table_resize (hash_table=0x8176fc0)
    at /tmp/buildd/glib2.0-2.14.6/glib/ghash.c:827
	node = (GHashNode *) 0x705f675f
	next = (GHashNode *) 0x0
	new_size = 13845163
	i = 1
#1  0xb7b0ad3b in IA__g_hash_table_remove (hash_table=0x8176fc0, key=0x2)
    at /tmp/buildd/glib2.0-2.14.6/glib/ghash.c:453
	node = (GHashNode **) 0x815b3d8
	__PRETTY_FUNCTION__ = "IA__g_hash_table_remove"
#2  0xb7c0966e in dbus_g_proxy_cancel_call (proxy=0x80e6b68, call=0x2)
    at dbus-gproxy.c:2678
	priv = (DBusGProxyPrivate *) 0x80e6b78
	__PRETTY_FUNCTION__ = "dbus_g_proxy_cancel_call"
#3  0xb7c7922b in tp_proxy_pending_call_cancel (self=0x8075598) at proxy.c:883
	iface = (gpointer) 0x80e6b68
	invoke = (
    TpProxyInvokeFunc) 0xb7c6fd70 <_tp_cli_media_stream_handler_invoke_callback_ready>
	__PRETTY_FUNCTION__ = "tp_proxy_pending_call_cancel"
#4  0xb7c793ba in tp_proxy_pending_call_lost_weak_ref (data=0x8075598, 
    dead=0x812c148) at proxy.c:681
	__PRETTY_FUNCTION__ = "tp_proxy_pending_call_lost_weak_ref"
#5  0xb7b94f21 in weak_refs_notify (data=0x81c4a00)
    at /tmp/buildd/glib2.0-2.14.6/gobject/gobject.c:1466
	i = 11
#6  0xb7b04fdf in IA__g_datalist_id_set_data_full (datalist=0x812c150, 
    key_id=80, data=0x0, destroy_func=0)
    at /tmp/buildd/glib2.0-2.14.6/glib/gdataset.c:242
	__PRETTY_FUNCTION__ = "IA__g_datalist_id_set_data_full"
#7  0xb7b95619 in g_object_real_dispose (object=0x812c148)
    at /tmp/buildd/glib2.0-2.14.6/gobject/gobject.c:534
No locals.
#8  0x08057550 in tp_stream_engine_stream_dispose (object=0x812c148)
    at stream.c:475
	stream = (TpStreamEngineStream *) 0x812c148
	priv = <value optimized out>
	__PRETTY_FUNCTION__ = "tp_stream_engine_stream_dispose"
Comment 1 Simon McVittie 2008-02-20 05:37:21 UTC
Fixed in HEAD and 0.7.3.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.