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];