Commit 86b257b4da for ffmpeg

commit 86b257b4da415ced3a065ffb666bcfbc99a87bc5
Author: Michael Niedermayer <michael@niedermayer.cc>
Date:   Mon Oct 12 02:30:15 2026 +0200

    avfilter/motion_estimation: use separate linesizes for the current and reference frame

    Fixes: out of array read
    Fixes: Au41rSBM5kGS
    Found during triage of the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24765
    Out of array read Replicated through UnModified FFmpeg with ASAN

diff --git a/libavfilter/motion_estimation.c b/libavfilter/motion_estimation.c
index 2bf5ce6155..a275e2bd6f 100644
--- a/libavfilter/motion_estimation.c
+++ b/libavfilter/motion_estimation.c
@@ -59,18 +59,19 @@ void ff_me_init_context(AVMotionEstContext *me_ctx, int mb_size, int search_para

 uint64_t ff_me_cmp_sad(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int x_mv, int y_mv)
 {
-    const int linesize = me_ctx->linesize;
+    const int linesize_ref = me_ctx->linesize_ref;
+    const int linesize_cur = me_ctx->linesize_cur;
     uint8_t *data_ref = me_ctx->data_ref;
     uint8_t *data_cur = me_ctx->data_cur;
     uint64_t sad = 0;
     int i, j;

-    data_ref += y_mv * linesize;
-    data_cur += y_mb * linesize;
+    data_ref += y_mv * linesize_ref;
+    data_cur += y_mb * linesize_cur;

     for (j = 0; j < me_ctx->mb_size; j++)
         for (i = 0; i < me_ctx->mb_size; i++)
-            sad += FFABS(data_ref[x_mv + i + j * linesize] - data_cur[x_mb + i + j * linesize]);
+            sad += FFABS(data_ref[x_mv + i + j * linesize_ref] - data_cur[x_mb + i + j * linesize_cur]);

     return sad;
 }
diff --git a/libavfilter/motion_estimation.h b/libavfilter/motion_estimation.h
index be627ec3b0..e5f69bec4a 100644
--- a/libavfilter/motion_estimation.h
+++ b/libavfilter/motion_estimation.h
@@ -40,7 +40,7 @@ typedef struct AVMotionEstPredictor {

 typedef struct AVMotionEstContext {
     uint8_t *data_cur, *data_ref;
-    int linesize;
+    int linesize_cur, linesize_ref;

     int mb_size;
     int search_param;
diff --git a/libavfilter/vf_mestimate.c b/libavfilter/vf_mestimate.c
index 759883df45..6c71a309f0 100644
--- a/libavfilter/vf_mestimate.c
+++ b/libavfilter/vf_mestimate.c
@@ -184,10 +184,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     }

     me_ctx->data_cur = s->cur->data[0];
-    me_ctx->linesize = s->cur->linesize[0];
+    me_ctx->linesize_cur = s->cur->linesize[0];

     for (dir = 0; dir < nb_dirs; dir++) {
-        me_ctx->data_ref = (dir ? s->next : s->prev)->data[0];
+        me_ctx->data_ref     = (dir ? s->next : s->prev)->data[0];
+        me_ctx->linesize_ref = (dir ? s->next : s->prev)->linesize[0];

         if (s->method == AV_ME_METHOD_DS)
             SEARCH_MV(ds);
diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c
index c996713553..75bffd4bf5 100644
--- a/libavfilter/vf_minterpolate.c
+++ b/libavfilter/vf_minterpolate.c
@@ -251,7 +251,8 @@ static uint64_t get_sbad(AVMotionEstContext *me_ctx, int x, int y, int x_mv, int
 {
     uint8_t *data_cur = me_ctx->data_cur;
     uint8_t *data_next = me_ctx->data_ref;
-    int linesize = me_ctx->linesize;
+    int linesize_cur  = me_ctx->linesize_cur;
+    int linesize_next = me_ctx->linesize_ref;
     int mv_x1 = x_mv - x;
     int mv_y1 = y_mv - y;
     int mv_x, mv_y, i, j;
@@ -262,12 +263,12 @@ static uint64_t get_sbad(AVMotionEstContext *me_ctx, int x, int y, int x_mv, int
     mv_x = av_clip(x_mv - x, -FFMIN(x - me_ctx->x_min, me_ctx->x_max - x), FFMIN(x - me_ctx->x_min, me_ctx->x_max - x));
     mv_y = av_clip(y_mv - y, -FFMIN(y - me_ctx->y_min, me_ctx->y_max - y), FFMIN(y - me_ctx->y_min, me_ctx->y_max - y));

-    data_cur += (y + mv_y) * linesize;
-    data_next += (y - mv_y) * linesize;
+    data_cur += (y + mv_y) * linesize_cur;
+    data_next += (y - mv_y) * linesize_next;

     for (j = 0; j < me_ctx->mb_size; j++)
         for (i = 0; i < me_ctx->mb_size; i++)
-            sbad += FFABS(data_cur[x + mv_x + i + j * linesize] - data_next[x - mv_x + i + j * linesize]);
+            sbad += FFABS(data_cur[x + mv_x + i + j * linesize_cur] - data_next[x - mv_x + i + j * linesize_next]);

     return sbad + (FFABS(mv_x1 - me_ctx->pred_x) + FFABS(mv_y1 - me_ctx->pred_y)) * COST_PRED_SCALE;
 }
@@ -276,7 +277,8 @@ static uint64_t get_sbad_ob(AVMotionEstContext *me_ctx, int x, int y, int x_mv,
 {
     uint8_t *data_cur = me_ctx->data_cur;
     uint8_t *data_next = me_ctx->data_ref;
-    int linesize = me_ctx->linesize;
+    int linesize_cur  = me_ctx->linesize_cur;
+    int linesize_next = me_ctx->linesize_ref;
     int x_min = me_ctx->x_min + me_ctx->mb_size / 2;
     int x_max = me_ctx->x_max - me_ctx->mb_size / 2;
     int y_min = me_ctx->y_min + me_ctx->mb_size / 2;
@@ -293,7 +295,7 @@ static uint64_t get_sbad_ob(AVMotionEstContext *me_ctx, int x, int y, int x_mv,

     for (j = -me_ctx->mb_size / 2; j < me_ctx->mb_size * 3 / 2; j++)
         for (i = -me_ctx->mb_size / 2; i < me_ctx->mb_size * 3 / 2; i++)
-            sbad += FFABS(data_cur[x + mv_x + i + (y + mv_y + j) * linesize] - data_next[x - mv_x + i + (y - mv_y + j) * linesize]);
+            sbad += FFABS(data_cur[x + mv_x + i + (y + mv_y + j) * linesize_cur] - data_next[x - mv_x + i + (y - mv_y + j) * linesize_next]);

     return sbad + (FFABS(mv_x1 - me_ctx->pred_x) + FFABS(mv_y1 - me_ctx->pred_y)) * COST_PRED_SCALE;
 }
@@ -302,7 +304,8 @@ static uint64_t get_sad_ob(AVMotionEstContext *me_ctx, int x, int y, int x_mv, i
 {
     uint8_t *data_ref = me_ctx->data_ref;
     uint8_t *data_cur = me_ctx->data_cur;
-    int linesize = me_ctx->linesize;
+    int linesize_ref = me_ctx->linesize_ref;
+    int linesize_cur = me_ctx->linesize_cur;
     int x_min = me_ctx->x_min + me_ctx->mb_size / 2;
     int x_max = me_ctx->x_max - me_ctx->mb_size / 2;
     int y_min = me_ctx->y_min + me_ctx->mb_size / 2;
@@ -319,7 +322,7 @@ static uint64_t get_sad_ob(AVMotionEstContext *me_ctx, int x, int y, int x_mv, i

     for (j = -me_ctx->mb_size / 2; j < me_ctx->mb_size * 3 / 2; j++)
         for (i = -me_ctx->mb_size / 2; i < me_ctx->mb_size * 3 / 2; i++)
-            sad += FFABS(data_ref[x_mv + i + (y_mv + j) * linesize] - data_cur[x + i + (y + j) * linesize]);
+            sad += FFABS(data_ref[x_mv + i + (y_mv + j) * linesize_ref] - data_cur[x + i + (y + j) * linesize_cur]);

     return sad + (FFABS(mv_x - me_ctx->pred_x) + FFABS(mv_y - me_ctx->pred_y)) * COST_PRED_SCALE;
 }
@@ -753,7 +756,8 @@ static int inject_frame(AVFilterLink *inlink, AVFrame *avf_in)

             if (mi_ctx->frames[1].avf) {
                 for (dir = 0; dir < 2; dir++) {
-                    mi_ctx->me_ctx.linesize = mi_ctx->frames[2].avf->linesize[0];
+                    mi_ctx->me_ctx.linesize_cur = mi_ctx->frames[2].avf->linesize[0];
+                    mi_ctx->me_ctx.linesize_ref = mi_ctx->frames[dir ? 3 : 1].avf->linesize[0];
                     mi_ctx->me_ctx.data_cur = mi_ctx->frames[2].avf->data[0];
                     mi_ctx->me_ctx.data_ref = mi_ctx->frames[dir ? 3 : 1].avf->data[0];

@@ -770,7 +774,8 @@ static int inject_frame(AVFilterLink *inlink, AVFrame *avf_in)
             if (!mi_ctx->frames[0].avf)
                 return 0;

-            mi_ctx->me_ctx.linesize = mi_ctx->frames[0].avf->linesize[0];
+            mi_ctx->me_ctx.linesize_cur = mi_ctx->frames[1].avf->linesize[0];
+            mi_ctx->me_ctx.linesize_ref = mi_ctx->frames[2].avf->linesize[0];
             mi_ctx->me_ctx.data_cur = mi_ctx->frames[1].avf->data[0];
             mi_ctx->me_ctx.data_ref = mi_ctx->frames[2].avf->data[0];