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.
This commit is contained in:
Michael Niedermayer authored and michaelni committed 2026-10-27 13:02:42 +00:00
1 parent 838c660bb3
commit 4221a63ce8
13 files changed
+45 -17

No files matched your search

+1
View File
@@ -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);
+1
View File
@@ -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,
+30 -17
View File
@@ -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;
+2
View File
@@ -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);
+1
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,
+2
View File
@@ -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,
+2
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,