Discussion:
[PATCH] flac: fix segfault when playing corrupt flac files
Johannes Weißl
2011-03-27 20:13:40 UTC
Permalink
Each FLAC frame has it's own number of channels. If the number of
channles is bigger than defined in STREAMINFO, cmus tries to access
non-existing channels and segfaults. This patch not only fixes the
segfault, but lets cmus decode the corrupt files.

Solves Ubuntu Bug #635231 [1].

[1] https://bugs.launchpad.net/ubuntu/+source/cmus/+bug/635231
---
flac.c | 17 ++++++++++-------
1 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/flac.c b/flac.c
index eec9e60..41dac45 100644
--- a/flac.c
+++ b/flac.c
@@ -187,7 +187,7 @@ static FLAC__StreamDecoderWriteStatus write_cb(const Dec *dec, const FLAC__Frame
struct input_plugin_data *ip_data = data;
struct flac_private *priv = ip_data->private;
int frames, bytes, size, channels, bits, depth;
- int ch, i, j = 0;
+ int ch, nch, i, j = 0;

if (ip_data->sf == 0) {
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
@@ -213,47 +213,50 @@ static FLAC__StreamDecoderWriteStatus write_cb(const Dec *dec, const FLAC__Frame
}

depth = frame->header.bits_per_sample;
+ if (!depth)
+ depth = bits;
+ nch = frame->header.channels;
if (depth == 8) {
char *b = priv->buf + priv->buf_wpos;

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = buf[ch][i];
+ b[j++] = buf[ch % nch][i];
}
} else if (depth == 16) {
int16_t *b = (int16_t *)(priv->buf + priv->buf_wpos);

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = LE16(buf[ch][i]);
+ b[j++] = LE16(buf[ch % nch][i]);
}
} else if (depth == 32) {
int32_t *b = (int32_t *)(priv->buf + priv->buf_wpos);

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = LE32(buf[ch][i]);
+ b[j++] = LE32(buf[ch % nch][i]);
}
} else if (depth == 12) { /* -> 16 */
int16_t *b = (int16_t *)(priv->buf + priv->buf_wpos);

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = LE16(buf[ch][i] << 4);
+ b[j++] = LE16(buf[ch % nch][i] << 4);
}
} else if (depth == 20) { /* -> 32 */
int32_t *b = (int32_t *)(priv->buf + priv->buf_wpos);

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = LE32(buf[ch][i] << 12);
+ b[j++] = LE32(buf[ch % nch][i] << 12);
}
} else if (depth == 24) { /* -> 32 */
int32_t *b = (int32_t *)(priv->buf + priv->buf_wpos);

for (i = 0; i < frames; i++) {
for (ch = 0; ch < channels; ch++)
- b[j++] = LE32(buf[ch][i] << 8);
+ b[j++] = LE32(buf[ch % nch][i] << 8);
}
} else {
d_print("bits per sample changed to %d\n", depth);
--
1.7.4.1
Johannes Weißl
2011-03-28 00:16:13 UTC
Permalink
Pulse plugin refuses to output audio files with more than two channels,
while oss and alsa plugins support this. Of course cmus does not handle
multi-channel correctly (no channel map), but at least pulse plays the
stereo subset now.

This is related to Ubuntu Bug #635231 [1]

[1] https://bugs.launchpad.net/ubuntu/+source/cmus/+bug/635231
---
pulse.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/pulse.c b/pulse.c
index fd2af57..75919a4 100644
--- a/pulse.c
+++ b/pulse.c
@@ -30,6 +30,7 @@ static pa_context *pa_ctx;
static pa_stream *pa_s;
static pa_channel_map pa_cmap;
static pa_cvolume pa_vol;
+static pa_sample_spec pa_ss;

/* configuration */
static int pa_restore_volume = 1;
@@ -317,6 +318,12 @@ static int op_pulse_open(sample_format_t sf)
if (!pa_sample_spec_valid(&ss))
return -OP_ERROR_SAMPLE_FORMAT;

+ pa_ss = ss;
+ /* can't be done in op_pulse_mixer_open() since channels is not known
+ * TODO: use correct channel map once sample_format_t is updated */
+ if (!pa_channel_map_init_auto(&pa_cmap, ss.channels, PA_CHANNEL_MAP_ALSA))
+ ret_pa_last_error();
+
rc = __pa_create_context();
if (rc)
return rc;
@@ -477,6 +484,7 @@ static int op_pulse_mixer_set_volume(int l, int r)
if (!pa_s && pa_restore_volume)
return -OP_ERROR_NOT_OPEN;

+ pa_cvolume_set(&pa_vol, pa_ss.channels, (pa_volume_t) ((l + r) / 2));
pa_cvolume_set_position(&pa_vol,
&pa_cmap,
PA_CHANNEL_POSITION_FRONT_LEFT,
--
1.7.4.1
Gregory Petrosyan
2011-03-29 08:49:11 UTC
Permalink
Post by Johannes Weißl
Pulse plugin refuses to output audio files with more than two channels,
while oss and alsa plugins support this. Of course cmus does not handle
multi-channel correctly (no channel map), but at least pulse plays the
stereo subset now.
This is related to Ubuntu Bug #635231 [1]
[1] https://bugs.launchpad.net/ubuntu/+source/cmus/+bug/635231
Merged both patches to both maint and master, thanks!

Gregory

Loading...