|
|
ecc610 |
From 1de3325c201dc0e1132bd34ea6f952ff8acbcf80 Mon Sep 17 00:00:00 2001
|
|
|
ecc610 |
From: Debarshi Ray <debarshir@freedesktop.org>
|
|
|
ecc610 |
Date: Fri, 16 Sep 2016 08:41:48 +0200
|
|
|
ecc610 |
Subject: [PATCH 2/2] Remove all queues before
|
|
|
ecc610 |
dleyna_task_processor_t->on_quit_cb is run
|
|
|
ecc610 |
|
|
|
ecc610 |
If dleyna_task_processor_t->on_quit_cb is run while there are still
|
|
|
ecc610 |
queues present in the processor, it can lead to a crash if one of the
|
|
|
ecc610 |
queue's task_queue_finally_cb handler didn't expect to be run after
|
|
|
ecc610 |
the control point has been stopped. For example,
|
|
|
ecc610 |
dleyna-renderer-service crashes with this backtrace:
|
|
|
ecc610 |
|
|
|
ecc610 |
%0 __GI_raise (sig=sig@entry=6)
|
|
|
ecc610 |
at ../sysdeps/unix/sysv/linux/raise.c:54
|
|
|
ecc610 |
%1 __GI_abort () at abort.c:89
|
|
|
ecc610 |
%2 g_assertion_message (domain="GLib",
|
|
|
ecc610 |
file="ghash.c",
|
|
|
ecc610 |
line=373,
|
|
|
ecc610 |
func="g_hash_table_lookup_node",
|
|
|
ecc610 |
message="assertion failed:
|
|
|
ecc610 |
(hash_table->ref_count > 0)")
|
|
|
ecc610 |
at gtestutils.c:2429
|
|
|
ecc610 |
%3 g_assertion_message_expr (domain="GLib",
|
|
|
ecc610 |
file="ghash.c",
|
|
|
ecc610 |
line=373,
|
|
|
ecc610 |
func="g_hash_table_lookup_node",
|
|
|
ecc610 |
expr="hash_table->ref_count > 0")
|
|
|
ecc610 |
at gtestutils.c:2452
|
|
|
ecc610 |
%4 g_hash_table_lookup_node (hash_return=<synthetic pointer>,
|
|
|
ecc610 |
key=0x561e98ca21c0,
|
|
|
ecc610 |
hash_table=0x561e985899e0)
|
|
|
ecc610 |
at ghash.c:373
|
|
|
ecc610 |
%5 g_hash_table_insert_internal (hash_table=0x561e985899e0,
|
|
|
ecc610 |
key=0x561e98ca21c0,
|
|
|
ecc610 |
value=0x561e98a581f0,
|
|
|
ecc610 |
keep_new_key=0)
|
|
|
ecc610 |
at ghash.c:1227
|
|
|
ecc610 |
%6 prv_device_chain_end (cancelled=<optimized out>,
|
|
|
ecc610 |
data=0x561e98e3acb0)
|
|
|
ecc610 |
at upnp.c:85
|
|
|
ecc610 |
%7 prv_free_cb (data=0x561e98b97280)
|
|
|
ecc610 |
at libdleyna/core/task-processor.c:103
|
|
|
ecc610 |
%8 g_hash_table_remove_all_nodes (hash_table=0x561e98549240,
|
|
|
ecc610 |
notify=<optimized out>,
|
|
|
ecc610 |
destruction=<optimized out>)
|
|
|
ecc610 |
at ghash.c:548
|
|
|
ecc610 |
%9 g_hash_table_remove_all_nodes (destruction=1,
|
|
|
ecc610 |
notify=1,
|
|
|
ecc610 |
hash_table=0x561e98549240)
|
|
|
ecc610 |
at ghash.c:1093
|
|
|
ecc610 |
%10 g_hash_table_unref (hash_table=0x561e98549240) at ghash.c:1097
|
|
|
ecc610 |
%11 dleyna_task_processor_free (processor=0x561e985543a0)
|
|
|
ecc610 |
at libdleyna/core/task-processor.c:136
|
|
|
ecc610 |
%12 prv_context_free () at libdleyna/core/main-loop.c:108
|
|
|
ecc610 |
%13 dleyna_main_loop_start (server=<optimized out>,
|
|
|
ecc610 |
control_point=<optimized out>,
|
|
|
ecc610 |
user_data=0x0)
|
|
|
ecc610 |
at libdleyna/core/main-loop.c:167
|
|
|
ecc610 |
%14 __libc_start_main (main=0x561e97db5990 <main>,
|
|
|
ecc610 |
argc=1,
|
|
|
ecc610 |
argv=0x7fff905cb0a8,
|
|
|
ecc610 |
init=<optimized out>,
|
|
|
ecc610 |
fini=<optimized out>,
|
|
|
ecc610 |
rtld_fini=<optimized out>,
|
|
|
ecc610 |
stack_end=0x7fff905cb098)
|
|
|
ecc610 |
at ../csu/libc-start.c:289
|
|
|
ecc610 |
%15 _start ()
|
|
|
ecc610 |
|
|
|
ecc610 |
The processor's on_quit_cb handler is set to prv_context_quit_cb,
|
|
|
ecc610 |
which calls control_point->stop_service and quits the GMainLoop. Then
|
|
|
ecc610 |
the processor is destroyed, which in turn destroys any queues that
|
|
|
ecc610 |
might have been left inside it. Unfortunately, a queue's
|
|
|
ecc610 |
task_queue_finally_cb handler might be set to something that assumes
|
|
|
ecc610 |
that the control_point has not been stopped. For example,
|
|
|
ecc610 |
dleyna-renderer-service sets task_queue_finally_cb to
|
|
|
ecc610 |
prv_device_chain_end, which will crash due to accessing invalid memory
|
|
|
ecc610 |
(specifically the dlr_upnp_t) if prv_control_point_stop_service has
|
|
|
ecc610 |
already been invoked. We see the same problem in dleyna-server-service
|
|
|
ecc610 |
too.
|
|
|
ecc610 |
|
|
|
ecc610 |
Therefore, let's remove any leftover queues from the processor just
|
|
|
ecc610 |
before dleyna_task_processor_t->on_quit_cb is scheduled to run. We are
|
|
|
ecc610 |
about to terminate the process anyway, so it shouldn't hurt to do it
|
|
|
ecc610 |
slightly earlier in the sequence.
|
|
|
ecc610 |
|
|
|
ecc610 |
https://bugzilla.redhat.com/show_bug.cgi?id=1360209
|
|
|
ecc610 |
---
|
|
|
ecc610 |
libdleyna/core/task-processor.c | 2 ++
|
|
|
ecc610 |
1 file changed, 2 insertions(+)
|
|
|
ecc610 |
|
|
|
ecc610 |
diff --git a/libdleyna/core/task-processor.c b/libdleyna/core/task-processor.c
|
|
|
ecc610 |
index 6d7f5b87de3d..89f0386c3f98 100644
|
|
|
ecc610 |
--- a/libdleyna/core/task-processor.c
|
|
|
ecc610 |
+++ b/libdleyna/core/task-processor.c
|
|
|
ecc610 |
@@ -257,6 +257,7 @@ void dleyna_task_processor_set_quitting(dleyna_task_processor_t *processor)
|
|
|
ecc610 |
g_idle_add(processor->on_quit_cb, NULL);
|
|
|
ecc610 |
|
|
|
ecc610 |
prv_cancel_all_queues(processor);
|
|
|
ecc610 |
+ g_hash_table_remove_all(processor->task_queues);
|
|
|
ecc610 |
|
|
|
ecc610 |
DLEYNA_LOG_DEBUG("Exit");
|
|
|
ecc610 |
}
|
|
|
ecc610 |
@@ -460,6 +461,7 @@ void dleyna_task_queue_task_completed(const dleyna_task_queue_key_t *queue_id)
|
|
|
ecc610 |
|
|
|
ecc610 |
if (processor->quitting && !processor->running_tasks) {
|
|
|
ecc610 |
g_idle_add(processor->on_quit_cb, NULL);
|
|
|
ecc610 |
+ g_hash_table_remove_all(processor->task_queues);
|
|
|
ecc610 |
} else if (queue->defer_remove) {
|
|
|
ecc610 |
DLEYNA_LOG_DEBUG("Removing queue <%s,%s>",
|
|
|
ecc610 |
queue_id->source, queue_id->sink);
|
|
|
ecc610 |
--
|
|
|
ecc610 |
2.7.4
|
|
|
ecc610 |
|