Commit 50e9ef29be for ffmpeg

commit 50e9ef29be1766404115b0a4908fa3fd6ed7fa3f
Author: Lynne <dev@lynne.ee>
Date:   Thu Dec 18 01:34:58 2025 +0100

    mjpegdec: use refstruct for the hwaccel_picture_private

    This was missed when the hwaccel_picture_private was made a buffer.

    Fixes: YMGIFa63VNkS
    Fixes: AISLE-2026-0150-00681
    Fixes: memleak
    Memleak Replicated through UnModified FFmpeg with ASAN

    Found-by: Joshua Rogers (AISLE)

    Cherry-picked from https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24652 where
    the commit is part of the Vulkan MJPEG hwaccel. The Fixes, replication and
    Found-by lines were added when applying it for the security report; the
    start_frame() call keeps passing NULL as the preceding commits of that pull
    request are not included.

diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 3716bbf753..1f11b6fbb7 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -824,15 +824,21 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)

     if (s->avctx->hwaccel) {
         const FFHWAccel *hwaccel = ffhwaccel(s->avctx->hwaccel);
-        s->hwaccel_picture_private =
-            av_mallocz(hwaccel->frame_priv_data_size);
-        if (!s->hwaccel_picture_private)
-            return AVERROR(ENOMEM);
+
+        /* A previous frame may have been aborted before its end_frame call,
+         * leaving the private data behind. */
+        av_refstruct_unref(&s->hwaccel_picture_private);
+
+        ret = ff_hwaccel_frame_priv_alloc(s->avctx, &s->hwaccel_picture_private);
+        if (ret < 0)
+            return ret;

         ret = hwaccel->start_frame(s->avctx, NULL, s->raw_image_buffer,
                                    s->raw_image_buffer_size);
-        if (ret < 0)
+        if (ret < 0) {
+            av_refstruct_unref(&s->hwaccel_picture_private);
             return ret;
+        }
     }

     return 0;
@@ -2582,7 +2588,7 @@ eoi_parser:
                 if (ret < 0)
                     return ret;

-                av_freep(&s->hwaccel_picture_private);
+                av_refstruct_unref(&s->hwaccel_picture_private);
             }
             if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
                 return ret;
@@ -2965,7 +2971,7 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)

     reset_icc_profile(s);

-    av_freep(&s->hwaccel_picture_private);
+    av_refstruct_unref(&s->hwaccel_picture_private);
     av_freep(&s->jls_state);

     return 0;
@@ -2976,6 +2982,8 @@ static av_cold void decode_flush(AVCodecContext *avctx)
     MJpegDecodeContext *s = avctx->priv_data;
     s->got_picture = 0;

+    av_refstruct_unref(&s->hwaccel_picture_private);
+
     s->smv_next_frame = 0;
     av_frame_unref(s->smv_frame);
 }