summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorJosé Roberto de Souza <jose.souza@intel.com>2014-12-17 16:57:03 -0200
committerJosé Roberto de Souza <jose.souza@intel.com>2014-12-17 17:05:35 -0200
commit63abe9b00cc02940361372cb0881d3f7fbb682f2 (patch)
treed8153706cb6489e608573dc80203894a96d1e8a3 /src/lib
parent78d5bb17d700f25e84abd5fb3eb4d42590c73474 (diff)
eldbus: Fix crash when removing the last reference of the message container inside of the message callback
If user try to remove the last reference of proxy, object, connection or eldbus(lib) inside of message callback it was causing the eldbus_pending_dispatch() being called 2 times, one because of the eldbus_cancel() that is triggered when the last reference of the message parent is removed and another after the return of the user callback. ==6545== Invalid read of size 8 ==6545== at 0x52F784E: eldbus_cbs_free_dispatch (eldbus_core.c:266) ==6545== by 0x53064AA: eldbus_pending_dispatch (eldbus_pending.c:227) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) ==6545== by 0x4E4B300: _ecore_call_task_cb (ecore_private.h:305) ==6545== by 0x4E4B78F: _ecore_idler_all_call (ecore_idler.c:143) ==6545== by 0x4E4EA73: _ecore_main_loop_spin_core (ecore_main.c:1768) ==6545== by 0x4E4EAF1: _ecore_main_loop_spin_timers (ecore_main.c:1802) ==6545== by 0x4E4ED01: _ecore_main_loop_iterate_internal (ecore_main.c:1925) ==6545== by 0x4E4D03B: ecore_main_loop_begin (ecore_main.c:983) ==6545== Address 0x701aa78 is 104 bytes inside a block of size 128 free'd ==6545== at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6545== by 0x530655B: eldbus_pending_dispatch (eldbus_pending.c:241) ==6545== by 0x5306763: eldbus_pending_cancel (eldbus_pending.c:259) ==6545== by 0x52F29DB: _eldbus_proxy_clear (eldbus_proxy.c:146) ==6545== by 0x52F3057: _eldbus_proxy_unref (eldbus_proxy.c:244) ==6545== by 0x52F3393: eldbus_proxy_unref (eldbus_proxy.c:264) ==6545== by 0x401039: on_get_playlists (banshee.c:53) ==6545== by 0x5306493: eldbus_pending_dispatch (eldbus_pending.c:225) ==6545== by 0x5305961: cb_pending (eldbus_pending.c:74) ==6545== by 0x6B29DB1: ??? (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x6B2D280: dbus_connection_dispatch (in /usr/lib/libdbus-1.so.3.8.9) ==6545== by 0x52F93B4: eldbus_idler (eldbus_core.c:773) Now we will remove the pending from parent pending list before call the user callback, this way only the pending messages will be canceled. Also we need increase the eldbus reference before call dbus_connection_dispatch() or user could remove the last reference of eldbus inside of a message callback when we still are holding one reference of the connection. @fix ref T1908
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/eldbus/eldbus_core.c2
-rw-r--r--src/lib/eldbus/eldbus_object.c21
-rw-r--r--src/lib/eldbus/eldbus_pending.c22
-rw-r--r--src/lib/eldbus/eldbus_proxy.c20
4 files changed, 47 insertions, 18 deletions
diff --git a/src/lib/eldbus/eldbus_core.c b/src/lib/eldbus/eldbus_core.c
index 71ee4e4c29..48ea7c01e9 100644
--- a/src/lib/eldbus/eldbus_core.c
+++ b/src/lib/eldbus/eldbus_core.c
@@ -769,9 +769,11 @@ eldbus_idler(void *data)
769 return ECORE_CALLBACK_CANCEL; 769 return ECORE_CALLBACK_CANCEL;
770 } 770 }
771 DBG("Connection@%p: Dispatching", conn); 771 DBG("Connection@%p: Dispatching", conn);
772 eldbus_init();
772 eldbus_connection_ref(conn); 773 eldbus_connection_ref(conn);
773 dbus_connection_dispatch(conn->dbus_conn); 774 dbus_connection_dispatch(conn->dbus_conn);
774 eldbus_connection_unref(conn); 775 eldbus_connection_unref(conn);
776 eldbus_shutdown();
775 return ECORE_CALLBACK_RENEW; 777 return ECORE_CALLBACK_RENEW;
776} 778}
777 779
diff --git a/src/lib/eldbus/eldbus_object.c b/src/lib/eldbus/eldbus_object.c
index 64047e622d..a859ba1daa 100644
--- a/src/lib/eldbus/eldbus_object.c
+++ b/src/lib/eldbus/eldbus_object.c
@@ -560,12 +560,15 @@ eldbus_object_path_get(const Eldbus_Object *obj)
560} 560}
561 561
562static void 562static void
563_on_pending_free(void *data, const void *dead_pointer) 563_on_object_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
564{ 564{
565 Eldbus_Object *obj = data; 565 Eldbus_Message_Cb cb = eldbus_pending_data_del(pending, "__user_cb");
566 Eldbus_Pending *pending = (Eldbus_Pending*) dead_pointer; 566 Eldbus_Object *obj = eldbus_pending_data_del(pending, "__object");
567
567 ELDBUS_OBJECT_CHECK(obj); 568 ELDBUS_OBJECT_CHECK(obj);
568 obj->pendings = eina_inlist_remove(obj->pendings, EINA_INLIST_GET(pending)); 569 obj->pendings = eina_inlist_remove(obj->pendings, EINA_INLIST_GET(pending));
570
571 cb(data, msg, pending);
569} 572}
570 573
571EAPI Eldbus_Pending * 574EAPI Eldbus_Pending *
@@ -576,11 +579,17 @@ eldbus_object_send(Eldbus_Object *obj, Eldbus_Message *msg, Eldbus_Message_Cb cb
576 ELDBUS_OBJECT_CHECK_RETVAL(obj, NULL); 579 ELDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
577 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL); 580 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
578 581
579 pending = _eldbus_connection_send(obj->conn, msg, cb, cb_data, timeout); 582 if (!cb)
580 if (!cb) return NULL; 583 {
584 _eldbus_connection_send(obj->conn, msg, NULL, NULL, timeout);
585 return NULL;
586 }
587 pending = _eldbus_connection_send(obj->conn, msg, _on_object_message_cb,
588 cb_data, timeout);
581 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL); 589 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
582 590
583 eldbus_pending_free_cb_add(pending, _on_pending_free, obj); 591 eldbus_pending_data_set(pending, "__user_cb", cb);
592 eldbus_pending_data_set(pending, "__object", obj);
584 obj->pendings = eina_inlist_append(obj->pendings, EINA_INLIST_GET(pending)); 593 obj->pendings = eina_inlist_append(obj->pendings, EINA_INLIST_GET(pending));
585 594
586 return pending; 595 return pending;
diff --git a/src/lib/eldbus/eldbus_pending.c b/src/lib/eldbus/eldbus_pending.c
index efa3970701..bd897b97d4 100644
--- a/src/lib/eldbus/eldbus_pending.c
+++ b/src/lib/eldbus/eldbus_pending.c
@@ -80,10 +80,14 @@ cleanup:
80} 80}
81 81
82static void 82static void
83_on_pending_free(void *data, const void *dead_pointer) 83_on_conn_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
84{ 84{
85 Eldbus_Connection *conn = data; 85 Eldbus_Message_Cb cb = eldbus_pending_data_del(pending, "__user_cb");
86 eldbus_connection_pending_del(conn, (void *)dead_pointer); 86 Eldbus_Connection *conn = eldbus_pending_data_del(pending, "__connection");
87
88 EINA_SAFETY_ON_NULL_RETURN(conn);
89 eldbus_connection_pending_del(conn, pending);
90 cb(data, msg, pending);
87} 91}
88 92
89EAPI Eldbus_Pending * 93EAPI Eldbus_Pending *
@@ -94,12 +98,18 @@ eldbus_connection_send(Eldbus_Connection *conn, Eldbus_Message *msg, Eldbus_Mess
94 EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL); 98 EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
95 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL); 99 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
96 100
97 pending = _eldbus_connection_send(conn, msg, cb, cb_data, timeout); 101 if (!cb)
98 if (!cb) return NULL; 102 {
103 _eldbus_connection_send(conn, msg, NULL, NULL, timeout);
104 return NULL;
105 }
106 pending = _eldbus_connection_send(conn, msg, _on_conn_message_cb, cb_data,
107 timeout);
99 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL); 108 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
100 109
110 eldbus_pending_data_set(pending, "__user_cb", cb);
111 eldbus_pending_data_set(pending, "__connection", conn);
101 eldbus_connection_pending_add(conn, pending); 112 eldbus_connection_pending_add(conn, pending);
102 eldbus_pending_free_cb_add(pending, _on_pending_free, conn);
103 return pending; 113 return pending;
104} 114}
105 115
diff --git a/src/lib/eldbus/eldbus_proxy.c b/src/lib/eldbus/eldbus_proxy.c
index 0d2ba15448..4d76a56090 100644
--- a/src/lib/eldbus/eldbus_proxy.c
+++ b/src/lib/eldbus/eldbus_proxy.c
@@ -521,13 +521,15 @@ eldbus_proxy_interface_get(const Eldbus_Proxy *proxy)
521} 521}
522 522
523static void 523static void
524_on_pending_free(void *data, const void *dead_pointer) 524_on_proxy_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
525{ 525{
526 Eldbus_Proxy *proxy = data; 526 Eldbus_Message_Cb cb = eldbus_pending_data_del(pending, "__user_cb");
527 Eldbus_Pending *pending = (Eldbus_Pending *)dead_pointer; 527 Eldbus_Proxy *proxy = eldbus_pending_data_del(pending, "__proxy");
528
528 ELDBUS_PROXY_CHECK(proxy); 529 ELDBUS_PROXY_CHECK(proxy);
529 proxy->pendings = eina_inlist_remove(proxy->pendings, 530 proxy->pendings = eina_inlist_remove(proxy->pendings,
530 EINA_INLIST_GET(pending)); 531 EINA_INLIST_GET(pending));
532 cb(data, msg, pending);
531} 533}
532 534
533static Eldbus_Pending * 535static Eldbus_Pending *
@@ -535,11 +537,17 @@ _eldbus_proxy_send(Eldbus_Proxy *proxy, Eldbus_Message *msg, Eldbus_Message_Cb c
535{ 537{
536 Eldbus_Pending *pending; 538 Eldbus_Pending *pending;
537 539
538 pending = _eldbus_connection_send(proxy->obj->conn, msg, cb, cb_data, timeout); 540 if (!cb)
539 if (!cb) return NULL; 541 {
542 _eldbus_connection_send(proxy->obj->conn, msg, NULL, NULL, timeout);
543 return NULL;
544 }
545 pending = _eldbus_connection_send(proxy->obj->conn, msg,
546 _on_proxy_message_cb, cb_data, timeout);
540 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL); 547 EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
541 548
542 eldbus_pending_free_cb_add(pending, _on_pending_free, proxy); 549 eldbus_pending_data_set(pending, "__user_cb", cb);
550 eldbus_pending_data_set(pending, "__proxy", proxy);
543 proxy->pendings = eina_inlist_append(proxy->pendings, 551 proxy->pendings = eina_inlist_append(proxy->pendings,
544 EINA_INLIST_GET(pending)); 552 EINA_INLIST_GET(pending));
545 553