Commit fdd4e83ea0 for ffmpeg

commit fdd4e83ea06e426558ded06f6b8d6ed9f752da21
Author: Prasanna Dabi <dabi.prasanna@gmail.com>
Date:   Tue Oct 20 07:49:28 2026 +0000

    avutil/hwcontext_vulkan: copy only the bytes of the visible rows

    copy_buffer_data() copied FFABS(linesize) bytes per row between the
    software frame and the staging buffer. The last row of a plane does not
    have to extend to the full linesize, so this read past the end of the
    software frame on upload and wrote past it on download.

    The staging path is always taken for frames with a negative linesize,
    and by default for multi-plane formats on the NVIDIA proprietary driver,
    where host image copies are disabled and host memory import is avoided.

    Same issue as fixed for hwcontext_cuda in f07f02abb864.

    Out of array read and write replicated through the API with ASAN.

diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 8e17f258f0..0ddfafb1b8 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -4725,6 +4725,15 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, FFVkBuffer *vkbuf,
 {
     int err;
     VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
+    int bytewidth[AV_NUM_DATA_POINTERS];
+
+    /* Copy only the visible bytes of each row, the last row of a plane
+     * does not have to extend to the full linesize. */
+    for (int i = 0; i < planes; i++) {
+        bytewidth[i] = av_image_get_linesize(swf->format, swf->width, i);
+        if (bytewidth[i] < 0)
+            return bytewidth[i];
+    }

     if (upload) {
         for (int i = 0; i < planes; i++)
@@ -4732,7 +4741,7 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, FFVkBuffer *vkbuf,
                                 region[i].bufferRowLength,
                                 swf->data[i],
                                 swf->linesize[i],
-                                FFABS(swf->linesize[i]),
+                                bytewidth[i],
                                 region[i].imageExtent.height);

         err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1);
@@ -4754,7 +4763,7 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, FFVkBuffer *vkbuf,
                                 swf->linesize[i],
                                 vkbuf->mapped_mem + region[i].bufferOffset,
                                 region[i].bufferRowLength,
-                                FFABS(swf->linesize[i]),
+                                bytewidth[i],
                                 region[i].imageExtent.height);
     }