PR #22587 opened by Zhao Zhili (quink)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22587
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22587.patch

When zx == -width (or zy == -height), the expression
  zx % width + width * (zx < 0)
yields width instead of a value in [0, width), causing OOB read.
Fix by only adding width when -width < zx < 0. For slideright and
slidedown where z is always non-negative, simply drop the dead
correction.

Also guard squeezeh/squeezev against division by zero when
progress == 0.

Fixes: #22273

Co-authored-by: scriptituk <[email protected]>
Signed-off-by: Zhao Zhili <[email protected]>


>From edc7148ed696fbc58cad0f2e6ca7b86873fd7039 Mon Sep 17 00:00:00 2001
From: Zhao Zhili <[email protected]>
Date: Mon, 23 Mar 2026 16:29:07 +0800
Subject: [PATCH] avfilter/vf_xfade: fix out-of-bounds index in
 slide/cover/reveal transitions

When zx == -width (or zy == -height), the expression
  zx % width + width * (zx < 0)
yields width instead of a value in [0, width), causing OOB read.
Fix by only adding width when -width < zx < 0. For slideright and
slidedown where z is always non-negative, simply drop the dead
correction.

Also guard squeezeh/squeezev against division by zero when
progress == 0.

Fixes: #22273

Co-authored-by: scriptituk <[email protected]>
Signed-off-by: Zhao Zhili <[email protected]>
---
 libavfilter/vf_xfade.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/libavfilter/vf_xfade.c b/libavfilter/vf_xfade.c
index 4517e4e6b3..2e2521197f 100644
--- a/libavfilter/vf_xfade.c
+++ b/libavfilter/vf_xfade.c
@@ -469,7 +469,7 @@ static void slideleft##name##_transition(AVFilterContext 
*ctx,
         for (int y = 0; y < height; y++) {                                     
      \
             for (int x = 0; x < width; x++) {                                  
      \
                 const int zx = z + x;                                          
      \
-                const int zz = zx % width + width * (zx < 0);                  
      \
+                const int zz = zx % width + width * (zx < 0 && zx > -width);   
      \
                 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz];        
      \
             }                                                                  
      \
                                                                                
      \
@@ -502,7 +502,7 @@ static void slideright##name##_transition(AVFilterContext 
*ctx,
         for (int y = 0; y < height; y++) {                                     
      \
             for (int x = 0; x < width; x++) {                                  
      \
                 const int zx = z + x;                                          
      \
-                const int zz = zx % width + width * (zx < 0);                  
      \
+                const int zz = zx % width;                                     
      \
                 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz];        
      \
             }                                                                  
      \
                                                                                
      \
@@ -532,7 +532,7 @@ static void slideup##name##_transition(AVFilterContext *ctx,
                                                                                
     \
         for (int y = slice_start; y < slice_end; y++) {                        
     \
             const int zy = z + y;                                              
     \
-            const int zz = zy % height + height * (zy < 0);                    
     \
+            const int zz = zy % height + height * (zy < 0 && zy > -height);    
     \
             const type *xf0 = (const type *)(a->data[p] + zz * 
a->linesize[p]);     \
             const type *xf1 = (const type *)(b->data[p] + zz * 
b->linesize[p]);     \
                                                                                
     \
@@ -564,7 +564,7 @@ static void slidedown##name##_transition(AVFilterContext 
*ctx,
                                                                                
     \
         for (int y = slice_start; y < slice_end; y++) {                        
     \
             const int zy = z + y;                                              
     \
-            const int zz = zy % height + height * (zy < 0);                    
     \
+            const int zz = zy % height;                                        
     \
             const type *xf0 = (const type *)(a->data[p] + zz * 
a->linesize[p]);     \
             const type *xf1 = (const type *)(b->data[p] + zz * 
b->linesize[p]);     \
                                                                                
     \
@@ -1633,7 +1633,7 @@ static void squeezeh##name##_transition(AVFilterContext 
*ctx,
         for (int y = 0; y < height; y++) {                                     
      \
             const float z = .5f + ((slice_start + y) / h - .5f) / progress;    
      \
                                                                                
      \
-            if (z < 0.f || z > 1.f) {                                          
      \
+            if (progress <= 0.f || z < 0.f || z > 1.f) {                       
      \
                 for (int x = 0; x < width; x++)                                
      \
                     dst[x] = xf1[x];                                           
      \
             } else {                                                           
      \
@@ -1673,7 +1673,7 @@ static void squeezev##name##_transition(AVFilterContext 
*ctx,
             for (int x = 0; x < width; x++) {                                  
      \
                 const float z = .5f + (x / w - .5f) / progress;                
      \
                                                                                
      \
-                if (z < 0.f || z > 1.f) {                                      
      \
+                if (progress <= 0.f || z < 0.f || z > 1.f) {                   
      \
                     dst[x] = xf1[x];                                           
      \
                 } else {                                                       
      \
                     const int xx = lrintf(z * (w - 1.f));                      
      \
@@ -1884,7 +1884,7 @@ static void cover##dir##name##_transition(AVFilterContext 
*ctx,
         for (int y = 0; y < height; y++) {                                     
      \
             for (int x = 0; x < width; x++) {                                  
      \
                 const int zx = z + x;                                          
      \
-                const int zz = zx % width + width * (zx < 0);                  
      \
+                const int zz = zx % width + width * (zx < 0 && zx > -width);   
      \
                 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[x];         
      \
             }                                                                  
      \
                                                                                
      \
@@ -1916,7 +1916,7 @@ static void cover##dir##name##_transition(AVFilterContext 
*ctx,
                                                                                
     \
         for (int y = slice_start; y < slice_end; y++) {                        
     \
             const int zy = z + y;                                              
     \
-            const int zz = zy % height + height * (zy < 0);                    
     \
+            const int zz = zy % height + height * (zy < 0 && zy > -height);    
     \
             const type *xf0 = (const type *)(a->data[p] +  y * 
a->linesize[p]);     \
             const type *xf1 = (const type *)(b->data[p] + zz * 
b->linesize[p]);     \
                                                                                
     \
@@ -1952,7 +1952,7 @@ static void 
reveal##dir##name##_transition(AVFilterContext *ctx,
         for (int y = 0; y < height; y++) {                                     
      \
             for (int x = 0; x < width; x++) {                                  
      \
                 const int zx = z + x;                                          
      \
-                const int zz = zx % width + width * (zx < 0);                  
      \
+                const int zz = zx % width + width * (zx < 0 && zx > -width);   
      \
                 dst[x] = (zx >= 0) && (zx < width) ? xf1[x] : xf0[zz];         
      \
             }                                                                  
      \
                                                                                
      \
@@ -1984,7 +1984,7 @@ static void 
reveal##dir##name##_transition(AVFilterContext *ctx,
                                                                                
     \
         for (int y = slice_start; y < slice_end; y++) {                        
     \
             const int zy = z + y;                                              
     \
-            const int zz = zy % height + height * (zy < 0);                    
     \
+            const int zz = zy % height + height * (zy < 0 && zy > -height);    
     \
             const type *xf0 = (const type *)(a->data[p] + zz * 
a->linesize[p]);     \
             const type *xf1 = (const type *)(b->data[p] +  y * 
b->linesize[p]);     \
                                                                                
     \
-- 
2.52.0

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

Reply via email to