diff options
author | David Henningsson <david.henningsson@canonical.com> | 2015-03-05 14:55:51 +0100 |
---|---|---|
committer | David Henningsson <david.henningsson@canonical.com> | 2015-03-11 12:43:02 +0100 |
commit | 7b8e8cd3883e081a6e3f2d8ed307524801438e04 (patch) | |
tree | 61dde3b7966491ae0670d3997f1a39292d327012 | |
parent | ebee1a63060f457171eafa93dea63e24264ac8e2 (diff) |
pstream: Don't split (non-SHM) memblocks
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>
-rw-r--r-- | src/pulsecore/pstream.c | 61 |
1 files changed, 25 insertions, 36 deletions
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index b0ed5a70f..877ff66c8 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -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); |