pstream: Don't split (non-SHM) memblocks
authorDavid Henningsson <david.henningsson@canonical.com>
Thu, 5 Mar 2015 13:55:51 +0000 (14:55 +0100)
committerDavid Henningsson <david.henningsson@canonical.com>
Wed, 11 Mar 2015 11:43:02 +0000 (12:43 +0100)
In case SHM is full or disabled, audio data is sent through the
io/srbchannel. When this channel in turn gets full, memblocks
could previously be split up. This could lead to crashes in case
the split was on non-frame boundaries (in combination with full
memblock queues).

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=88452
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
src/pulsecore/pstream.c

index b0ed5a7..877ff66 100644 (file)
@@ -682,6 +682,30 @@ fail:
     return -1;
 }
 
+static void memblock_complete(pa_pstream *p, struct pstream_read *re) {
+    pa_memchunk chunk;
+    int64_t offset;
+
+    if (!p->receive_memblock_callback)
+        return;
+
+    chunk.memblock = re->memblock;
+    chunk.index = 0;
+    chunk.length = re->index - PA_PSTREAM_DESCRIPTOR_SIZE;
+
+    offset = (int64_t) (
+             (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) |
+             (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO]))));
+
+    p->receive_memblock_callback(
+        p,
+        ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]),
+        offset,
+        ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK,
+        &chunk,
+        p->receive_memblock_callback_userdata);
+}
+
 static int do_read(pa_pstream *p, struct pstream_read *re) {
     void *d;
     size_t l;
@@ -831,47 +855,12 @@ static int do_read(pa_pstream *p, struct pstream_read *re) {
         }
 
     } else if (re->index > PA_PSTREAM_DESCRIPTOR_SIZE) {
-        /* Frame payload available */
-
-        if (re->memblock && p->receive_memblock_callback) {
-
-            /* Is this memblock data? Than pass it to the user */
-            l = (re->index - (size_t) r) < PA_PSTREAM_DESCRIPTOR_SIZE ? (size_t) (re->index - PA_PSTREAM_DESCRIPTOR_SIZE) : (size_t) r;
-
-            if (l > 0) {
-                pa_memchunk chunk;
-
-                chunk.memblock = re->memblock;
-                chunk.index = re->index - PA_PSTREAM_DESCRIPTOR_SIZE - l;
-                chunk.length = l;
-
-                if (p->receive_memblock_callback) {
-                    int64_t offset;
-
-                    offset = (int64_t) (
-                            (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) |
-                            (((uint64_t) ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO]))));
-
-                    p->receive_memblock_callback(
-                        p,
-                        ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]),
-                        offset,
-                        ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK,
-                        &chunk,
-                        p->receive_memblock_callback_userdata);
-                }
-
-                /* Drop seek info for following callbacks */
-                re->descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] =
-                    re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] =
-                    re->descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0;
-            }
-        }
 
         /* Frame complete */
         if (re->index >= ntohl(re->descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) {
 
             if (re->memblock) {
+                memblock_complete(p, re);
 
                 /* This was a memblock frame. We can unref the memblock now */
                 pa_memblock_unref(re->memblock);