From 86b257b4da415ced3a065ffb666bcfbc99a87bc5 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Mon, 12 Oct 2026 02:30:15 +0200 Subject: [PATCH] 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 --- libavfilter/motion_estimation.c | 9 +++++---- libavfilter/motion_estimation.h | 2 +- libavfilter/vf_mestimate.c | 5 +++-- libavfilter/vf_minterpolate.c | 25 +++++++++++++++---------- 4 files changed, 24 insertions(+), 17 deletions(-) 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];