[FFmpeg-cvslog] avcodec/mpeg12dec: Use saturated addition when combining error_count

Andreas Rheinhardt git at videolan.org
Mon Mar 17 04:51:07 EET 2025


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Fri Mar 14 19:10:57 2025 +0100| [2742de0e4a46c9c824fb8ab4cc3013c4988238e3] | committer: Andreas Rheinhardt

avcodec/mpeg12dec: Use saturated addition when combining error_count

Fixes undefined integer overflows. The overflows could always
happen, yet before 4d8b706b1d33e75eb30b289c152280d4535c40e6
it was not undefined because the code implicitly used atomic
types, for which signed integer overflow is defined.

Reported-by: Kacper Michajlow <kasper93 at gmail.com>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=2742de0e4a46c9c824fb8ab4cc3013c4988238e3
---

 libavcodec/mpeg12dec.c | 62 +++++++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 29 deletions(-)

diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index ffe0710470..efb66ef956 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -2233,6 +2233,36 @@ static int mpeg_decode_gop(AVCodecContext *avctx,
     return 0;
 }
 
+static void mpeg12_execute_slice_threads(AVCodecContext *avctx,
+                                         Mpeg1Context *const s)
+{
+    if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) &&
+        !avctx->hwaccel) {
+        MpegEncContext *const s2 = &s->mpeg_enc_ctx;
+        int error_count = 0;
+        av_assert0(avctx->thread_count > 1);
+
+        avctx->execute(avctx, slice_decode_thread,
+                       s2->thread_context, NULL,
+                       s->slice_count, sizeof(void *));
+
+        for (int i = 0; i < s->slice_count; i++) {
+            MpegEncContext *const slice = s2->thread_context[i];
+            int slice_err = atomic_load_explicit(&slice->er.error_count,
+                                                 memory_order_relaxed);
+            // error_count can get set to INT_MAX on serious errors.
+            // So use saturated addition.
+            if ((unsigned)slice_err > INT_MAX - error_count) {
+                error_count = INT_MAX;
+                break;
+            }
+            error_count += slice_err;
+        }
+        atomic_store_explicit(&s2->er.error_count, error_count,
+                              memory_order_relaxed);
+    }
+}
+
 static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
                          int *got_output, const uint8_t *buf, int buf_size)
 {
@@ -2250,22 +2280,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
         buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &start_code);
         if (start_code > 0x1ff) {
             if (!skip_frame) {
-                if (HAVE_THREADS &&
-                    (avctx->active_thread_type & FF_THREAD_SLICE) &&
-                    !avctx->hwaccel) {
-                    int error_count = 0;
-                    int i;
-                    av_assert0(avctx->thread_count > 1);
-
-                    avctx->execute(avctx, slice_decode_thread,
-                                   &s2->thread_context[0], NULL,
-                                   s->slice_count, sizeof(void *));
-                    for (i = 0; i < s->slice_count; i++)
-                        error_count += atomic_load_explicit(&s2->thread_context[i]->er.error_count,
-                                                            memory_order_relaxed);
-                    atomic_store_explicit(&s2->er.error_count, error_count,
-                                          memory_order_relaxed);
-                }
+                mpeg12_execute_slice_threads(avctx, s);
 
                 ret = slice_end(avctx, picture, got_output);
                 if (ret < 0)
@@ -2324,19 +2339,8 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
                 s2->intra_dc_precision= 3;
                 s2->intra_matrix[0]= 1;
             }
-            if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) &&
-                !avctx->hwaccel && s->slice_count) {
-                int error_count = 0;
-                int i;
-
-                avctx->execute(avctx, slice_decode_thread,
-                               s2->thread_context, NULL,
-                               s->slice_count, sizeof(void *));
-                for (i = 0; i < s->slice_count; i++)
-                    error_count += atomic_load_explicit(&s2->thread_context[i]->er.error_count,
-                                                        memory_order_relaxed);
-                atomic_store_explicit(&s2->er.error_count, error_count,
-                                      memory_order_relaxed);
+            if (s->slice_count) {
+                mpeg12_execute_slice_threads(avctx, s);
                 s->slice_count = 0;
             }
             if (last_code == 0 || last_code == SLICE_MIN_START_CODE) {



More information about the ffmpeg-cvslog mailing list