[FFmpeg-cvslog] avcodec/h264: Fix race between slices where one overwrites data from the next

Michael Niedermayer git at videolan.org
Sat Apr 11 22:12:28 CEST 2015


ffmpeg | branch: release/2.6 | Michael Niedermayer <michaelni at gmx.at> | Tue Apr  7 00:40:21 2015 +0200| [d3f96c1e3cc291d32616a2ab25d16a44d2170a36] | committer: Michael Niedermayer

avcodec/h264: Fix race between slices where one overwrites data from the next

Fixes non deterministic crash in ticket4408/fuzz2.264
Likely fixes other samples as well

Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
(cherry picked from commit 43b434210e597d484aef57c4139c3126d22b7e2b)

Conflicts:

	libavcodec/h264.h
	libavcodec/h264_slice.c

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

 libavcodec/h264.h       |    1 +
 libavcodec/h264_slice.c |   43 ++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index 21e9952..a9a351d 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -536,6 +536,7 @@ typedef struct H264Context {
     int mb_x, mb_y;
     int resync_mb_x;
     int resync_mb_y;
+    int mb_index_end;
     int mb_skip_run;
     int mb_height, mb_width;
     int mb_stride;
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 0071e6e..c8728b5 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -2425,8 +2425,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
 
         for (;;) {
             // START_TIMER
-            int ret = ff_h264_decode_mb_cabac(h);
-            int eos;
+            int ret, eos;
+
+            if (h->mb_x + h->mb_y * h->mb_width >= h->mb_index_end) {
+                av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n",
+                       h->mb_index_end);
+                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,
+                             h->mb_y, ER_MB_ERROR);
+                return AVERROR_INVALIDDATA;
+            }
+
+            ret = ff_h264_decode_mb_cabac(h);
             // STOP_TIMER("decode_mb_cabac")
 
             if (ret >= 0)
@@ -2488,7 +2497,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
         }
     } else {
         for (;;) {
-            int ret = ff_h264_decode_mb_cavlc(h);
+            int ret;
+
+            if (h->mb_x + h->mb_y * h->mb_width >= h->mb_index_end) {
+                av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n",
+                       h->mb_index_end);
+                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,
+                             h->mb_y, ER_MB_ERROR);
+                return AVERROR_INVALIDDATA;
+            }
+
+            ret = ff_h264_decode_mb_cavlc(h);
 
             if (ret >= 0)
                 ff_h264_hl_decode_mb(h);
@@ -2576,19 +2595,33 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
 
     av_assert0(h->mb_y < h->mb_height);
 
+    h->mb_index_end = INT_MAX;
+
     if (h->avctx->hwaccel ||
         h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
         return 0;
     if (context_count == 1) {
         return decode_slice(avctx, &h);
     } else {
+        int j, mb_index;
         av_assert0(context_count > 0);
-        for (i = 1; i < context_count; i++) {
+        for (i = 0; i < context_count; i++) {
+            int mb_index_end = h->mb_width * h->mb_height;
             hx                 = h->thread_context[i];
-            if (CONFIG_ERROR_RESILIENCE) {
+            mb_index = hx->resync_mb_x + hx->resync_mb_y * h->mb_width;
+            if (CONFIG_ERROR_RESILIENCE && i) {
                 hx->er.error_count = 0;
             }
             hx->x264_build     = h->x264_build;
+            for (j = 0; j < context_count; j++) {
+                H264Context *sl2 = h->thread_context[j];
+                int mb_index2 = sl2->resync_mb_x + sl2->resync_mb_y * h->mb_width;
+
+                if (i==j || mb_index > mb_index2)
+                    continue;
+                mb_index_end = FFMIN(mb_index_end, mb_index2);
+            }
+            hx->mb_index_end = mb_index_end;
         }
 
         avctx->execute(avctx, decode_slice, h->thread_context,



More information about the ffmpeg-cvslog mailing list