PR #24382 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24382 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24382.patch
Fixes: nan_pad_test.c This PR depends on one commit from https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24381 (which is why theres a 2nd commit in this PR) >From 619aae3a90e259cd47cf05f9ff98117be6f88dde Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 6 Sep 2026 01:57:34 +0200 Subject: [PATCH 1/2] swscale/ops_dispatch: account for the vertical filter taps in the tail copy Fixes: out of array read Fixes: ffmpeg -cpuflags 0 -i poc_input.ppm -vf scale=17:17:flags=unstable -pix_fmt rgba -f rawvideo - Fixes: sAlT1ubFAGko --- libswscale/ops_dispatch.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c index ac5e0b6438..b08dda9a3e 100644 --- a/libswscale/ops_dispatch.c +++ b/libswscale/ops_dispatch.c @@ -54,6 +54,7 @@ typedef struct SwsOpPass { int palette_idx; int *offsets_y; int filter_size_h; + int filter_size_v; bool memcpy_first; bool memcpy_last; bool memcpy_out; @@ -166,7 +167,7 @@ static inline int get_lines_in(const SwsOpPass *p, const int y, const int h, return h >> base->in_sub_y[plane]; const int y0 = p->offsets_y[y] >> base->in_sub_y[plane]; - const int y1 = p->offsets_y[y + h - 1] >> base->in_sub_y[plane]; + const int y1 = (p->offsets_y[y + h - 1] + p->filter_size_v - 1) >> base->in_sub_y[plane]; return y1 - y0 + 1; } @@ -400,8 +401,11 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, * memcpy the last column on the output side if unpadded. */ - const bool memcpy_in = p->memcpy_last && y + h == pass->lines || - p->memcpy_first && y == 0; + const int y_in_first = p->offsets_y ? p->offsets_y[y] : y; + const int y_in_last = p->offsets_y ? p->offsets_y[y + h - 1] + p->filter_size_v - 1 + : y + h - 1; + const bool memcpy_in = p->memcpy_last && y_in_last == in->height - 1 || + p->memcpy_first && y_in_first == 0; const bool memcpy_out = p->memcpy_out; const size_t num_blocks = p->num_blocks; const size_t tail_blocks = p->tail_blocks; @@ -435,7 +439,7 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, /* Input offsets are relative to the base pointer */ if (!exec.in_offset_x || memcpy_in) exec.in[i] += p->tail_off_in; - tail.in[i] += y * tail.in_stride[i]; + tail.in[i] += (y_in_first >> exec.in_sub_y[i]) * tail.in_stride[i]; } for (int i = 0; i < p->planes_out; i++) { exec.out[i] += p->tail_off_out; @@ -640,6 +644,7 @@ static int compile_single(const CompileArgs *args, const SwsOpList *ops, const SwsFilterWeights *filter = read ? read->rw.filter.kernel : NULL; if (read && read->rw.filter.op == SWS_OP_FILTER_V) { p->offsets_y = av_refstruct_ref(filter->offsets); + p->filter_size_v = filter->filter_size; /* Compute relative pointer bumps for each output line */ int32_t *bump = av_malloc_array(filter->dst_size, sizeof(*bump)); -- 2.52.0 >From dd53ce8000bb78a5d76ff4c1c8ea66ff5a2dad92 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 6 Sep 2026 05:37:09 +0200 Subject: [PATCH 2/2] swscale/ops_dispatch: fix leaking NaN from outside the picture into it Fixes: nan_pad_test.c --- libswscale/ops_dispatch.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c index b08dda9a3e..7fa4c90e8f 100644 --- a/libswscale/ops_dispatch.c +++ b/libswscale/ops_dispatch.c @@ -55,8 +55,7 @@ typedef struct SwsOpPass { int *offsets_y; int filter_size_h; int filter_size_v; - bool memcpy_first; - bool memcpy_last; + bool memcpy_in; bool memcpy_out; size_t tail_blocks; uint8_t *tail_buf; /* extra memory for fixing unpadded tails */ @@ -223,8 +222,7 @@ static int op_pass_setup(const SwsFrame *out, const SwsFrame *in, if (aligned_w < width) /* overflow */ return AVERROR(EINVAL); p->num_blocks = num_blocks; - p->memcpy_first = false; - p->memcpy_last = false; + p->memcpy_in = false; p->memcpy_out = false; size_t safe_blocks = num_blocks; @@ -250,8 +248,7 @@ static int op_pass_setup(const SwsFrame *out, const SwsFrame *in, } if (safe_blocks_in < num_blocks) { - p->memcpy_first |= in->linesize[idx] < 0; - p->memcpy_last |= in->linesize[idx] > 0; + p->memcpy_in = true; safe_blocks = FFMIN(safe_blocks, safe_blocks_in); } @@ -281,7 +278,7 @@ static int op_pass_setup(const SwsFrame *out, const SwsFrame *in, exec->in_stride[1] = exec->in_bump[1] = 0; } - const bool memcpy_in = p->memcpy_first || p->memcpy_last; + const bool memcpy_in = p->memcpy_in; if (!memcpy_in && !p->memcpy_out) { av_assert0(safe_blocks == num_blocks); return 0; @@ -391,10 +388,10 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, * To ensure safety, we need to consider the following: * * 1. We can overread the input, unless this is the last line of an - * unpadded buffer. All defined operations can handle arbitrary pixel - * input, so overread of arbitrary data is fine. For flipped images, - * this condition is actually *inverted* to where the first line is - * the one at the end of the buffer. + * unpadded buffer (the first line for flipped images). A vertical + * filter lets any slice read that line, so every slice of an + * unpadded input takes the memcpy path. All defined operations can + * handle arbitrary pixel input, so overread of arbitrary data is fine. * * 2. We can overwrite the output, as long as we don't write more than the * amount of pixels that fit into one linesize. So we always need to @@ -402,10 +399,7 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, */ const int y_in_first = p->offsets_y ? p->offsets_y[y] : y; - const int y_in_last = p->offsets_y ? p->offsets_y[y + h - 1] + p->filter_size_v - 1 - : y + h - 1; - const bool memcpy_in = p->memcpy_last && y_in_last == in->height - 1 || - p->memcpy_first && y_in_first == 0; + const bool memcpy_in = p->memcpy_in; const bool memcpy_out = p->memcpy_out; const size_t num_blocks = p->num_blocks; const size_t tail_blocks = p->tail_blocks; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
