libopusenc: cherry-pick post-release crash fixes
authorAndre Heider <a.heider@gmail.com>
Fri, 9 Jul 2021 06:45:23 +0000 (08:45 +0200)
committerAndre Heider <a.heider@gmail.com>
Sat, 31 Jul 2021 11:38:28 +0000 (13:38 +0200)
Fixes crashes like:
daemon.err asterisk[5087]: Assertion failed: enc->streams == NULL (src/opusenc.c: ope_encoder_drain: 839)

Signed-off-by: Andre Heider <a.heider@gmail.com>
libs/libopusenc/patches/0001-Fix-ope_encoder_drain-assertion-failure.patch [new file with mode: 0644]
libs/libopusenc/patches/0002-Fix-use-of-uninitialized-fields.patch [new file with mode: 0644]
libs/libopusenc/patches/0003-Fix-use-of-uninitialized-serialno.patch [new file with mode: 0644]

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 (file)
index 0000000..7c0ba06
--- /dev/null
@@ -0,0 +1,27 @@
+From 205552370e058d99452fd34983942e10f2db6dff Mon Sep 17 00:00:00 2001
+From: Mark Harris <mark.hsj@gmail.com>
+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 (file)
index 0000000..8642e2f
--- /dev/null
@@ -0,0 +1,78 @@
+From 6d46f2d7f7617852bab7cbb2f7cae8350b99204e Mon Sep 17 00:00:00 2001
+From: Mark Harris <mark.hsj@gmail.com>
+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 (file)
index 0000000..cf5cf56
--- /dev/null
@@ -0,0 +1,47 @@
+From 427d61131a1af5eed48d5428e723ab4602b56cc1 Mon Sep 17 00:00:00 2001
+From: Mark Harris <mark.hsj@gmail.com>
+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;