libao: Avoid segfault on com_cycle.
authorAndre Noll <maan@systemlinux.org>
Thu, 3 Feb 2011 16:15:27 +0000 (17:15 +0100)
committerAndre Noll <maan@systemlinux.org>
Fri, 6 May 2011 20:12:06 +0000 (22:12 +0200)
Executing the cycle command while the ao writer is active can lead to
a segmentation fault because kill_all_decoders() removes the buffer
tree node of the ao writer but leaves its child node alive.

This patch changes kill_all_decoders() to kill the receiver node only
while leaving all other nodes alone, removing the assumption that
the set of filter nodes and writer nodes are the only nodes in the
buffer tree. This assumption used to be true but became false with
the merge of the ao writer which has two buffer tree nodes.

It is enough to kill only the receiver node as all other nodes will
eventually notice that their parent node no longer exists and exit
shortly thereafter.

audiod.c

index 9f664e178309c39e70a64d7ea55f6a29f0c5f6cf..6a4c9dbead6c61bbaaedfb484369749404dbe7b5 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -429,22 +429,15 @@ static void kill_btrn(struct btr_node *btrn, struct task *t, int error)
 
 static void kill_all_decoders(int error)
 {
 
 static void kill_all_decoders(int error)
 {
-       int i, j;
+       int i;
 
        FOR_EACH_SLOT(i) {
 
        FOR_EACH_SLOT(i) {
-               struct slot_info *s = &slot[i];
-               struct audio_format_info *a;
+               struct slot_info *s = slot + i;
                if (s->format < 0)
                        continue;
                if (s->format < 0)
                        continue;
-               a = afi + s->format;
-               if (s->wns)
-                       for (j = 0; j < a->num_writers; j++)
-                               kill_btrn(s->wns[j].btrn, &s->wns[j].task, error);
-               if (s->fns)
-                       for (j = 0; j < a->num_writers; j++)
-                               kill_btrn(s->fns[j].btrn, &s->wns[j].task, error);
-               if (s->receiver_node)
-                       kill_btrn(s->receiver_node->btrn, &s->receiver_node->task,
+               if (!s->receiver_node)
+                       continue;
+               kill_btrn(s->receiver_node->btrn, &s->receiver_node->task,
                                error);
        }
 }
                                error);
        }
 }