Commit 95d27d9f05 for ffmpeg
commit 95d27d9f056920d35724f4b90d1e55258f41ec9a
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Thu Oct 15 04:32:07 2026 +0200
avfilter/vf_fieldmatch: use the chroma subsampling when marking combed chroma
Fixes: out of array write
Fixes: z4YbWg6eX0Hr
Found during triage/review of the security report 0fHkOzVCAhre
Out of array write Replicated through UnModified FFmpeg with ASAN
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
index 384714f23d..8624bdb91a 100644
--- a/libavfilter/vf_fieldmatch.c
+++ b/libavfilter/vf_fieldmatch.c
@@ -34,6 +34,7 @@
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/timestamp.h"
@@ -195,6 +196,40 @@ static void fill_buf(uint8_t *data, int w, int h, int linesize, uint8_t v)
}
}
+static av_always_inline void mark_combed_chroma(const FieldMatchContext *fm, const AVFrame *src,
+ int hsub, int vsub)
+{
+ const uint8_t *cmkpU = fm->cmask_data[1];
+ const uint8_t *cmkpV = fm->cmask_data[2];
+ const int width = AV_CEIL_RSHIFT(src->width, hsub);
+ const int height = AV_CEIL_RSHIFT(src->height, vsub);
+ const ptrdiff_t cmk_linesize = fm->cmask_linesize[0];
+ const ptrdiff_t cmk_linesizeUV = fm->cmask_linesize[2];
+
+ for (int y = 1; y < height - 1; y++) {
+ uint8_t *cmkp_row = fm->cmask_data[0] + ((y << vsub) - (vsub ? y & 1 : 0)) * cmk_linesize;
+ cmkpV += cmk_linesizeUV;
+ cmkpU += cmk_linesizeUV;
+ for (int x = 1; x < width - 1; x++) {
+#define HAS_FF_AROUND(p, lz) (p[(x)-1 - (lz)] == 0xff || p[(x) - (lz)] == 0xff || p[(x)+1 - (lz)] == 0xff || \
+ p[(x)-1 ] == 0xff || p[(x)+1 ] == 0xff || \
+ p[(x)-1 + (lz)] == 0xff || p[(x) + (lz)] == 0xff || p[(x)+1 + (lz)] == 0xff)
+ if ((cmkpV[x] == 0xff && HAS_FF_AROUND(cmkpV, cmk_linesizeUV)) ||
+ (cmkpU[x] == 0xff && HAS_FF_AROUND(cmkpU, cmk_linesizeUV))) {
+ uint8_t *cmkp = cmkp_row + (x << hsub);
+ for (int i = 0; i < (1 << vsub) + !!vsub; i++, cmkp += cmk_linesize) {
+ if (hsub == 2)
+ AV_WN32A(cmkp, 0xffffffff);
+ else if (hsub)
+ AV_WN16A(cmkp, 0xffff);
+ else
+ *cmkp = 0xff;
+ }
+ }
+ }
+ }
+}
+
static int calc_combed_score(const FieldMatchContext *fm, const AVFrame *src)
{
int x, y, plane, max_v = 0;
@@ -271,36 +306,13 @@ static int calc_combed_score(const FieldMatchContext *fm, const AVFrame *src)
}
if (fm->chroma) {
- uint8_t *cmkp = fm->cmask_data[0];
- uint8_t *cmkpU = fm->cmask_data[1];
- uint8_t *cmkpV = fm->cmask_data[2];
- const int width = AV_CEIL_RSHIFT(src->width, fm->hsub[INPUT_MAIN]);
- const int height = AV_CEIL_RSHIFT(src->height, fm->vsub[INPUT_MAIN]);
- const int cmk_linesize = fm->cmask_linesize[0] << 1;
- const int cmk_linesizeUV = fm->cmask_linesize[2];
- uint8_t *cmkpp = cmkp - (cmk_linesize>>1);
- uint8_t *cmkpn = cmkp + (cmk_linesize>>1);
- uint8_t *cmkpnn = cmkp + cmk_linesize;
- for (y = 1; y < height - 1; y++) {
- cmkpp += cmk_linesize;
- cmkp += cmk_linesize;
- cmkpn += cmk_linesize;
- cmkpnn += cmk_linesize;
- cmkpV += cmk_linesizeUV;
- cmkpU += cmk_linesizeUV;
- for (x = 1; x < width - 1; x++) {
-#define HAS_FF_AROUND(p, lz) (p[(x)-1 - (lz)] == 0xff || p[(x) - (lz)] == 0xff || p[(x)+1 - (lz)] == 0xff || \
- p[(x)-1 ] == 0xff || p[(x)+1 ] == 0xff || \
- p[(x)-1 + (lz)] == 0xff || p[(x) + (lz)] == 0xff || p[(x)+1 + (lz)] == 0xff)
- if ((cmkpV[x] == 0xff && HAS_FF_AROUND(cmkpV, cmk_linesizeUV)) ||
- (cmkpU[x] == 0xff && HAS_FF_AROUND(cmkpU, cmk_linesizeUV))) {
- ((uint16_t*)cmkp)[x] = 0xffff;
- ((uint16_t*)cmkpn)[x] = 0xffff;
- if (y&1) ((uint16_t*)cmkpp)[x] = 0xffff;
- else ((uint16_t*)cmkpnn)[x] = 0xffff;
- }
- }
- }
+ const int hsub = fm->hsub[INPUT_MAIN];
+ const int vsub = fm->vsub[INPUT_MAIN];
+ if (hsub == 0 && vsub == 0) mark_combed_chroma(fm, src, 0, 0);
+ else if (hsub == 1 && vsub == 0) mark_combed_chroma(fm, src, 1, 0);
+ else if (hsub == 1 && vsub == 1) mark_combed_chroma(fm, src, 1, 1);
+ else if (hsub == 2 && vsub == 0) mark_combed_chroma(fm, src, 2, 0);
+ else mark_combed_chroma(fm, src, hsub, vsub);
}
{