PR #23510 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23510
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23510.patch

The stride was not enough to cover the input width ...


>From 1219fef95e8e1ac6a2debdcd823d9d30bc447d3a Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Mon, 15 Jun 2026 19:00:00 +0200
Subject: [PATCH 1/3] checkasm/sw_rgb: fix too small source stride in
 uyvytoyuv422 test

The planes table stored a source stride smaller than the 2*width bytes a
packed UYVY line occupies (e.g. width 12 with stride 12), and the correct
stride for width 128 would be 256, which does not even fit the uint8_t
field. The test passed only because the oversized source buffer absorbed
the resulting out-of-bounds reads.

Derive srcStride from the width (2*width) instead of storing it, so each
line is passed its true size.

Signed-off-by: Michael Niedermayer <[email protected]>
---
 tests/checkasm/sw_rgb.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c
index a38e1d68f5..7a3049ddd1 100644
--- a/tests/checkasm/sw_rgb.c
+++ b/tests/checkasm/sw_rgb.c
@@ -38,8 +38,8 @@
     } while (0)
 
 static const uint8_t width[] = {12, 16, 20, 32, 36, 128};
-static const struct {uint8_t w, h, s;} planes[] = {
-    {12,16,12}, {16,16,16}, {20,23,25}, {32,18,48}, {8,128,16}, {128,128,128}
+static const struct {uint8_t w, h;} planes[] = {
+    {12,16}, {16,16}, {20,23}, {32,18}, {8,128}, {128,128}
 };
 
 #define MAX_STRIDE 128
@@ -93,6 +93,9 @@ static void check_uyvy_to_422p(void)
 
     if (check_func(uyvytoyuv422, "uyvytoyuv422")) {
         for (i = 0; i < 6; i ++) {
+            int w = planes[i].w, h = planes[i].h;
+            int srcStride = 2 * w;
+
             memset(dst_y_0, 0, MAX_STRIDE * MAX_HEIGHT);
             memset(dst_y_1, 0, MAX_STRIDE * MAX_HEIGHT);
             memset(dst_u_0, 0, (MAX_STRIDE/2) * MAX_HEIGHT);
@@ -100,17 +103,17 @@ static void check_uyvy_to_422p(void)
             memset(dst_v_0, 0, (MAX_STRIDE/2) * MAX_HEIGHT);
             memset(dst_v_1, 0, (MAX_STRIDE/2) * MAX_HEIGHT);
 
-            call_ref(dst_y_0, dst_u_0, dst_v_0, src0, planes[i].w, planes[i].h,
-                     MAX_STRIDE, MAX_STRIDE / 2, planes[i].s);
-            call_new(dst_y_1, dst_u_1, dst_v_1, src1, planes[i].w, planes[i].h,
-                     MAX_STRIDE, MAX_STRIDE / 2, planes[i].s);
+            call_ref(dst_y_0, dst_u_0, dst_v_0, src0, w, h,
+                     MAX_STRIDE, MAX_STRIDE / 2, srcStride);
+            call_new(dst_y_1, dst_u_1, dst_v_1, src1, w, h,
+                     MAX_STRIDE, MAX_STRIDE / 2, srcStride);
             if (memcmp(dst_y_0, dst_y_1, MAX_STRIDE * MAX_HEIGHT) ||
                 memcmp(dst_u_0, dst_u_1, (MAX_STRIDE/2) * MAX_HEIGHT) ||
                 memcmp(dst_v_0, dst_v_1, (MAX_STRIDE/2) * MAX_HEIGHT))
                 fail();
         }
         bench_new(dst_y_1, dst_u_1, dst_v_1, src1, planes[5].w, planes[5].h,
-                  MAX_STRIDE, MAX_STRIDE / 2, planes[5].s);
+                  MAX_STRIDE, MAX_STRIDE / 2, 2 * planes[5].w);
     }
 }
 
-- 
2.52.0


>From 9e2693b21f3e6f1e9b0285c9efeb7e22c542a15e Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Mon, 15 Jun 2026 19:00:26 +0200
Subject: [PATCH 2/3] checkasm/sw_rgb: test uyvytoyuv422 with odd widths

The SIMD uyvytoyuv422 implementations only handled even widths correctly.
Add odd width and 1x1 entries so the trailing column handling is exercised
against the C reference.

An odd width reads one source byte more than 2*width, the V sample at
src[2w], so the stride is extended by one for odd widths.

Signed-off-by: Michael Niedermayer <[email protected]>
---
 tests/checkasm/sw_rgb.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c
index 7a3049ddd1..53bde765db 100644
--- a/tests/checkasm/sw_rgb.c
+++ b/tests/checkasm/sw_rgb.c
@@ -39,7 +39,8 @@
 
 static const uint8_t width[] = {12, 16, 20, 32, 36, 128};
 static const struct {uint8_t w, h;} planes[] = {
-    {12,16}, {16,16}, {20,23}, {32,18}, {8,128}, {128,128}
+    {12,16}, {16,16}, {20,23}, {32,18}, {8,128}, {128,128},
+    {1,1}, {1,4}, {3,8}, {13,16}, {21,9}, {63,7}, {127,5}
 };
 
 #define MAX_STRIDE 128
@@ -92,9 +93,9 @@ static void check_uyvy_to_422p(void)
     memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT * 2);
 
     if (check_func(uyvytoyuv422, "uyvytoyuv422")) {
-        for (i = 0; i < 6; i ++) {
+        for (i = 0; i < FF_ARRAY_ELEMS(planes); i ++) {
             int w = planes[i].w, h = planes[i].h;
-            int srcStride = 2 * w;
+            int srcStride = 2 * w + (w & 1);   // UYVY odd width reads V at 
src[2w]
 
             memset(dst_y_0, 0, MAX_STRIDE * MAX_HEIGHT);
             memset(dst_y_1, 0, MAX_STRIDE * MAX_HEIGHT);
-- 
2.52.0


>From 8c94b3869c0fcabb194f7dbab3b36ade9d9fa2b0 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Mon, 15 Jun 2026 22:12:41 +0200
Subject: [PATCH 3/3] checkasm/sw_rgb: also test yuyvtoyuv422

yuyvtoyuv422 reads the trailing odd V sample at src[2w+1], one byte further
than uyvytoyuv422, so the number of extra source bytes an odd width needs is
passed in per format (1 for UYVY, 2 for YUYV) and added to the stride.

uyvytoyuv420 and yuyvtoyuv420 are intentionally not added: their x86 mmxext
chroma averaging uses PAVGB rounding and so is not bit-exact with the C
reference, which truncates, so they cannot be verified this way.

Signed-off-by: Michael Niedermayer <[email protected]>
---
 tests/checkasm/sw_rgb.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c
index 53bde765db..7bf5d8e175 100644
--- a/tests/checkasm/sw_rgb.c
+++ b/tests/checkasm/sw_rgb.c
@@ -72,7 +72,7 @@ static void check_shuffle_bytes(void * func, const char * 
report)
     }
 }
 
-static void check_uyvy_to_422p(void)
+static void check_interleaved_to_planar(void *func, const char *report, int 
odd_tail)
 {
     int i;
 
@@ -92,10 +92,10 @@ static void check_uyvy_to_422p(void)
     randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT * 2);
     memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT * 2);
 
-    if (check_func(uyvytoyuv422, "uyvytoyuv422")) {
+    if (check_func(func, "%s", report)) {
         for (i = 0; i < FF_ARRAY_ELEMS(planes); i ++) {
             int w = planes[i].w, h = planes[i].h;
-            int srcStride = 2 * w + (w & 1);   // UYVY odd width reads V at 
src[2w]
+            int srcStride = 2 * w + (w & 1 ? odd_tail : 0);
 
             memset(dst_y_0, 0, MAX_STRIDE * MAX_HEIGHT);
             memset(dst_y_1, 0, MAX_STRIDE * MAX_HEIGHT);
@@ -960,8 +960,10 @@ void checkasm_check_sw_rgb(void)
     }
     report("rgb24tobgr32");
 
-    check_uyvy_to_422p();
+    check_interleaved_to_planar(uyvytoyuv422, "uyvytoyuv422", 1);
     report("uyvytoyuv422");
+    check_interleaved_to_planar(yuyvtoyuv422, "yuyvtoyuv422", 2);
+    report("yuyvtoyuv422");
 
     check_interleave_bytes();
     report("interleave_bytes");
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to