Commit 4221a63ce8 for ffmpeg
commit 4221a63ce869ade862557ca64693bf77f5032971
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Sat Oct 17 03:22:33 2026 +0200
avcodec/vaapi_decode: destroy the buffers of a picture released without being issued
mjpegdec releases a picture left over from a failed packet before
ff_get_format() tears down the VA context and the device the callback needs.
Fixes: vMMlgSzb6MuU
Fixes: AISLE-2026-0150-00741
Fixes: memleak
Memleak Replicated through UnModified FFmpeg with ASAN
Found-by: Joshua Rogers (AISLE)
The report suggested a free_frame_priv callback that destroys the still
tracked parameter and slice buffers.
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index f50bb556eb..8002ca191a 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -761,6 +761,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
s->avctx->pix_fmt,
AV_PIX_FMT_NONE,
};
+ av_refstruct_unref(&s->hwaccel_picture_private);
s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts);
if (s->hwaccel_pix_fmt < 0)
return AVERROR(EINVAL);
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index d00bb601a5..02fe5246e4 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -456,6 +456,7 @@ const FFHWAccel ff_av1_vaapi_hwaccel = {
.end_frame = vaapi_av1_end_frame,
.decode_slice = vaapi_av1_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = ff_vaapi_decode_free_frame_priv,
.init = vaapi_av1_decode_init,
.uninit = vaapi_av1_decode_uninit,
.frame_params = ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 4ac2df5b43..e7f5545dba 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -135,34 +135,44 @@ int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
return 0;
}
-static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
+static void ff_vaapi_decode_destroy_buffers(void *logctx, VADisplay display,
VAAPIDecodePicture *pic)
{
- VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
int i;
for (i = 0; i < pic->nb_param_buffers; i++) {
- vas = vaDestroyBuffer(ctx->hwctx->display,
- pic->param_buffers[i]);
+ vas = vaDestroyBuffer(display, pic->param_buffers[i]);
if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
+ av_log(logctx, AV_LOG_ERROR, "Failed to destroy "
"parameter buffer %#x: %d (%s).\n",
pic->param_buffers[i], vas, vaErrorStr(vas));
}
}
for (i = 0; i < 2 * pic->nb_slices; i++) {
- vas = vaDestroyBuffer(ctx->hwctx->display,
- pic->slice_buffers[i]);
+ vas = vaDestroyBuffer(display, pic->slice_buffers[i]);
if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice "
+ av_log(logctx, AV_LOG_ERROR, "Failed to destroy slice "
"slice buffer %#x: %d (%s).\n",
pic->slice_buffers[i], vas, vaErrorStr(vas));
}
}
}
+static void vaapi_decode_free_buffers(void *logctx, VADisplay display,
+ VAAPIDecodePicture *pic)
+{
+ ff_vaapi_decode_destroy_buffers(logctx, display, pic);
+
+ pic->nb_param_buffers = 0;
+ pic->nb_param_buffers_allocated = 0;
+ av_freep(&pic->param_buffers);
+ pic->nb_slices = 0;
+ pic->nb_slice_buffers_allocated = 0;
+ av_freep(&pic->slice_buffers);
+}
+
int ff_vaapi_decode_issue(AVCodecContext *avctx,
VAAPIDecodePicture *pic)
{
@@ -219,7 +229,7 @@ int ff_vaapi_decode_issue(AVCodecContext *avctx,
if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
- ff_vaapi_decode_destroy_buffers(avctx, pic);
+ ff_vaapi_decode_destroy_buffers(avctx, ctx->hwctx->display, pic);
err = 0;
goto exit;
@@ -231,7 +241,7 @@ fail_with_picture:
"after error: %d (%s).\n", vas, vaErrorStr(vas));
}
fail:
- ff_vaapi_decode_destroy_buffers(avctx, pic);
+ ff_vaapi_decode_destroy_buffers(avctx, ctx->hwctx->display, pic);
fail_at_end:
exit:
pic->nb_param_buffers = 0;
@@ -247,18 +257,21 @@ exit:
int ff_vaapi_decode_cancel(AVCodecContext *avctx,
VAAPIDecodePicture *pic)
{
- ff_vaapi_decode_destroy_buffers(avctx, pic);
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
- pic->nb_param_buffers = 0;
- pic->nb_param_buffers_allocated = 0;
- av_freep(&pic->param_buffers);
- pic->nb_slices = 0;
- pic->nb_slice_buffers_allocated = 0;
- av_freep(&pic->slice_buffers);
+ vaapi_decode_free_buffers(avctx, ctx->hwctx->display, pic);
return 0;
}
+void ff_vaapi_decode_free_frame_priv(AVRefStructOpaque hwctx, void *data)
+{
+ AVHWDeviceContext *device_ctx = hwctx.nc;
+ AVVAAPIDeviceContext *vactx = device_ctx->hwctx;
+
+ vaapi_decode_free_buffers(device_ctx, vactx->display, data);
+}
+
static const struct {
uint32_t fourcc;
enum AVPixelFormat pix_fmt;
diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h
index 7813473c98..2c696c7891 100644
--- a/libavcodec/vaapi_decode.h
+++ b/libavcodec/vaapi_decode.h
@@ -24,6 +24,7 @@
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_vaapi.h"
+#include "libavutil/refstruct.h"
#include "avcodec.h"
@@ -79,6 +80,7 @@ int ff_vaapi_decode_issue(AVCodecContext *avctx,
VAAPIDecodePicture *pic);
int ff_vaapi_decode_cancel(AVCodecContext *avctx,
VAAPIDecodePicture *pic);
+void ff_vaapi_decode_free_frame_priv(AVRefStructOpaque hwctx, void *data);
int ff_vaapi_decode_init(AVCodecContext *avctx);
int ff_vaapi_decode_uninit(AVCodecContext *avctx);
diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c
index 7f00da09fc..32ecc97c66 100644
--- a/libavcodec/vaapi_h264.c
+++ b/libavcodec/vaapi_h264.c
@@ -403,6 +403,7 @@ const FFHWAccel ff_h264_vaapi_hwaccel = {
.end_frame = &vaapi_h264_end_frame,
.decode_slice = &vaapi_h264_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c
index 3d0f6632fd..4a0202570b 100644
--- a/libavcodec/vaapi_hevc.c
+++ b/libavcodec/vaapi_hevc.c
@@ -665,6 +665,7 @@ const FFHWAccel ff_hevc_vaapi_hwaccel = {
.end_frame = vaapi_hevc_end_frame,
.decode_slice = vaapi_hevc_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePictureHEVC),
+ .free_frame_priv = ff_vaapi_decode_free_frame_priv,
.init = ff_vaapi_decode_init,
.uninit = ff_vaapi_decode_uninit,
.frame_params = ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c
index c8b59b8afa..bc05e336a6 100644
--- a/libavcodec/vaapi_mjpeg.c
+++ b/libavcodec/vaapi_mjpeg.c
@@ -152,6 +152,7 @@ const FFHWAccel ff_mjpeg_vaapi_hwaccel = {
.end_frame = &vaapi_mjpeg_end_frame,
.decode_slice = &vaapi_mjpeg_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c
index 07bf35c532..b2a4bc4094 100644
--- a/libavcodec/vaapi_mpeg2.c
+++ b/libavcodec/vaapi_mpeg2.c
@@ -185,6 +185,7 @@ const FFHWAccel ff_mpeg2_vaapi_hwaccel = {
.end_frame = &vaapi_mpeg2_end_frame,
.decode_slice = &vaapi_mpeg2_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c
index d936a290cd..81f0f357ad 100644
--- a/libavcodec/vaapi_mpeg4.c
+++ b/libavcodec/vaapi_mpeg4.c
@@ -192,6 +192,7 @@ const FFHWAccel ff_mpeg4_vaapi_hwaccel = {
.end_frame = &vaapi_mpeg4_end_frame,
.decode_slice = &vaapi_mpeg4_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
@@ -210,6 +211,7 @@ const FFHWAccel ff_h263_vaapi_hwaccel = {
.end_frame = &vaapi_mpeg4_end_frame,
.decode_slice = &vaapi_mpeg4_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c
index 42171918e8..7bb2d27055 100644
--- a/libavcodec/vaapi_vc1.c
+++ b/libavcodec/vaapi_vc1.c
@@ -516,6 +516,7 @@ const FFHWAccel ff_wmv3_vaapi_hwaccel = {
.end_frame = &vaapi_vc1_end_frame,
.decode_slice = &vaapi_vc1_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
@@ -533,6 +534,7 @@ const FFHWAccel ff_vc1_vaapi_hwaccel = {
.end_frame = &vaapi_vc1_end_frame,
.decode_slice = &vaapi_vc1_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c
index b9b1f2aa51..ec226d5386 100644
--- a/libavcodec/vaapi_vp8.c
+++ b/libavcodec/vaapi_vp8.c
@@ -230,6 +230,7 @@ const FFHWAccel ff_vp8_vaapi_hwaccel = {
.end_frame = &vaapi_vp8_end_frame,
.decode_slice = &vaapi_vp8_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c
index 7d57f340e0..f113de96ef 100644
--- a/libavcodec/vaapi_vp9.c
+++ b/libavcodec/vaapi_vp9.c
@@ -178,6 +178,7 @@ const FFHWAccel ff_vp9_vaapi_hwaccel = {
.end_frame = vaapi_vp9_end_frame,
.decode_slice = vaapi_vp9_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
+ .free_frame_priv = ff_vaapi_decode_free_frame_priv,
.init = ff_vaapi_decode_init,
.uninit = ff_vaapi_decode_uninit,
.frame_params = ff_vaapi_common_frame_params,
diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c
index f5ee07ee87..175aaba5b1 100644
--- a/libavcodec/vaapi_vvc.c
+++ b/libavcodec/vaapi_vvc.c
@@ -650,6 +650,7 @@ const FFHWAccel ff_vvc_vaapi_hwaccel = {
.end_frame = &vaapi_vvc_end_frame,
.decode_slice = &vaapi_vvc_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePictureVVC),
+ .free_frame_priv = &ff_vaapi_decode_free_frame_priv,
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,