From 7200d1386ce596cf85d5ab33d80e4ad09f278ea1 Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 9 Jul 2021 08:45:23 +0200 Subject: [PATCH] libopusenc: cherry-pick post-release crash fixes Fixes crashes like: daemon.err asterisk[5087]: Assertion failed: enc->streams == NULL (src/opusenc.c: ope_encoder_drain: 839) Signed-off-by: Andre Heider --- ...-ope_encoder_drain-assertion-failure.patch | 27 +++++++ ...0002-Fix-use-of-uninitialized-fields.patch | 78 +++++++++++++++++++ ...03-Fix-use-of-uninitialized-serialno.patch | 47 +++++++++++ 3 files changed, 152 insertions(+) create mode 100644 libs/libopusenc/patches/0001-Fix-ope_encoder_drain-assertion-failure.patch create mode 100644 libs/libopusenc/patches/0002-Fix-use-of-uninitialized-fields.patch create mode 100644 libs/libopusenc/patches/0003-Fix-use-of-uninitialized-serialno.patch diff --git a/libs/libopusenc/patches/0001-Fix-ope_encoder_drain-assertion-failure.patch b/libs/libopusenc/patches/0001-Fix-ope_encoder_drain-assertion-failure.patch new file mode 100644 index 000000000..7c0ba068a --- /dev/null +++ b/libs/libopusenc/patches/0001-Fix-ope_encoder_drain-assertion-failure.patch @@ -0,0 +1,27 @@ +From 205552370e058d99452fd34983942e10f2db6dff Mon Sep 17 00:00:00 2001 +From: Mark Harris +Date: Mon, 28 Dec 2020 12:58:17 -0800 +Subject: [PATCH] Fix ope_encoder_drain() assertion failure + +If the stream is drained without writing any audio and the frame size is +smaller than the encoder latency, the assertion (enc->streams == NULL) +would fail because pad_samples was computed using an incorrect value of +enc->global_granule_offset before it was set in init_stream(), causing +the padding to be insufficient to drain the stream. +--- + src/opusenc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/src/opusenc.c ++++ b/src/opusenc.c +@@ -808,9 +808,9 @@ int ope_encoder_drain(OggOpusEnc *enc) { + if (enc->unrecoverable) return enc->unrecoverable; + /* Check if it's already been drained. */ + if (enc->streams == NULL) return OPE_TOO_LATE; ++ if (!enc->streams->stream_is_init) init_stream(enc); + if (enc->re) resampler_drain = speex_resampler_get_output_latency(enc->re); + pad_samples = MAX(LPC_PADDING, enc->global_granule_offset + enc->frame_size + resampler_drain + 1); +- if (!enc->streams->stream_is_init) init_stream(enc); + shift_buffer(enc); + assert(enc->buffer_end + pad_samples <= BUFFER_SAMPLES); + memset(&enc->buffer[enc->channels*enc->buffer_end], 0, pad_samples*enc->channels*sizeof(enc->buffer[0])); diff --git a/libs/libopusenc/patches/0002-Fix-use-of-uninitialized-fields.patch b/libs/libopusenc/patches/0002-Fix-use-of-uninitialized-fields.patch new file mode 100644 index 000000000..8642e2fff --- /dev/null +++ b/libs/libopusenc/patches/0002-Fix-use-of-uninitialized-fields.patch @@ -0,0 +1,78 @@ +From 6d46f2d7f7617852bab7cbb2f7cae8350b99204e Mon Sep 17 00:00:00 2001 +From: Mark Harris +Date: Mon, 28 Dec 2020 17:01:39 -0800 +Subject: [PATCH] Fix use of uninitialized fields + +enc->streams->end_granule used uninitialized in encode_buffer() if the +stream contains no audio (opusenc_example /dev/null out.opus). + +enc->frame_size_request used uninitialized in encode_buffer() if the +frame size was not explicitly set. + +enc->callbacks used uninitialized if the encoder is created with +ope_encoder_create_callbacks() and callbacks is NULL. +--- + src/opusenc.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +--- a/src/opusenc.c ++++ b/src/opusenc.c +@@ -361,8 +361,7 @@ static void stream_destroy(EncStream *st + free(stream); + } + +-/* Create a new OggOpus file (callback-based). */ +-OggOpusEnc *ope_encoder_create_callbacks(const OpusEncCallbacks *callbacks, void *user_data, ++static OggOpusEnc *ope_encoder_create_callbacks_impl(const OpusEncCallbacks *callbacks, void *user_data, + OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error) { + OggOpusEnc *enc=NULL; + int ret; +@@ -395,11 +394,11 @@ OggOpusEnc *ope_encoder_create_callbacks + enc->oggp = NULL; + /* Not initializing anything is an unrecoverable error. */ + enc->unrecoverable = family == -1 ? OPE_TOO_LATE : 0; +- enc->pull_api = 0; + enc->packet_callback = NULL; + enc->rate = rate; + enc->channels = channels; + enc->frame_size = 960; ++ enc->frame_size_request = OPUS_FRAMESIZE_20_MS; + enc->decision_delay = 96000; + enc->max_ogg_delay = 48000; + enc->chaining_keyframe = NULL; +@@ -447,8 +446,12 @@ OggOpusEnc *ope_encoder_create_callbacks + if (callbacks != NULL) + { + enc->callbacks = *callbacks; ++ enc->pull_api = 0; ++ } else { ++ enc->pull_api = 1; + } + enc->streams->user_data = user_data; ++ enc->streams->end_granule = 0; + if (error) *error = OPE_OK; + return enc; + fail: +@@ -462,11 +465,19 @@ fail: + return NULL; + } + ++/* Create a new OggOpus stream (callback-based). */ ++OggOpusEnc *ope_encoder_create_callbacks(const OpusEncCallbacks *callbacks, void *user_data, ++ OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error) { ++ if (callbacks == NULL) { ++ if (error) *error = OPE_BAD_ARG; ++ return NULL; ++ } ++ return ope_encoder_create_callbacks_impl(callbacks, user_data, comments, rate, channels, family, error); ++} ++ + /* Create a new OggOpus stream, pulling one page at a time. */ + OggOpusEnc *ope_encoder_create_pull(OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error) { +- OggOpusEnc *enc = ope_encoder_create_callbacks(NULL, NULL, comments, rate, channels, family, error); +- if (enc) enc->pull_api = 1; +- return enc; ++ return ope_encoder_create_callbacks_impl(NULL, NULL, comments, rate, channels, family, error); + } + + int ope_encoder_deferred_init_with_mapping(OggOpusEnc *enc, int family, int streams, diff --git a/libs/libopusenc/patches/0003-Fix-use-of-uninitialized-serialno.patch b/libs/libopusenc/patches/0003-Fix-use-of-uninitialized-serialno.patch new file mode 100644 index 000000000..cf5cf5608 --- /dev/null +++ b/libs/libopusenc/patches/0003-Fix-use-of-uninitialized-serialno.patch @@ -0,0 +1,47 @@ +From 427d61131a1af5eed48d5428e723ab4602b56cc1 Mon Sep 17 00:00:00 2001 +From: Mark Harris +Date: Tue, 29 Dec 2020 01:43:37 -0800 +Subject: [PATCH] Fix use of uninitialized serialno + +Also do not crash if OPE_GET_SERIALNO_REQUEST is used after draining. +--- + src/opusenc.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/src/opusenc.c ++++ b/src/opusenc.c +@@ -356,6 +356,11 @@ fail: + return NULL; + } + ++static void stream_generate_serialno(EncStream *stream) { ++ stream->serialno = rand(); ++ stream->serialno_is_set = 1; ++} ++ + static void stream_destroy(EncStream *stream) { + if (stream->comment) free(stream->comment); + free(stream); +@@ -512,9 +517,7 @@ int ope_encoder_deferred_init_with_mappi + + static void init_stream(OggOpusEnc *enc) { + assert(!enc->streams->stream_is_init); +- if (!enc->streams->serialno_is_set) { +- enc->streams->serialno = rand(); +- } ++ if (!enc->streams->serialno_is_set) stream_generate_serialno(enc->streams); + + if (enc->oggp != NULL) oggp_chain(enc->oggp, enc->streams->serialno); + else { +@@ -1071,6 +1074,11 @@ int ope_encoder_ctl(OggOpusEnc *enc, int + case OPE_GET_SERIALNO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); ++ if (!enc->last_stream) { ++ ret = OPE_TOO_LATE; ++ break; ++ } ++ if (!enc->last_stream->serialno_is_set) stream_generate_serialno(enc->last_stream); + *value = enc->last_stream->serialno; + } + break;