Commit b90ec19645 for ffmpeg
commit b90ec196453748b3c83e434d38e7abaae5f2dbb2
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Sun Oct 11 07:22:27 2026 +0200
avcodec/pthread_frame: give each worker context its own copy of the channel layout
The worker contexts are created by av_memdup() of the user context, a
custom channel layout map was shared with all of them. Copying the
layout into the first worker in update_context_from_thread() freed the
shared map and read it afterwards, decoders which uninit the layout in
init freed it twice.
Fixes: heap use after free
Fixes: double free
Fixes: l08oZE4M5Rmz
Regression since: 548aeb9383
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24577
Heap use after free Replicated through UnModified FFmpeg with ASAN
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 5ec9a8a974..085aff5508 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -790,6 +790,7 @@ av_cold void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
ff_pthread_free(p, per_thread_offsets);
av_packet_free(&p->avpkt);
+ av_channel_layout_uninit(&ctx->ch_layout);
av_freep(&p->avctx);
}
@@ -821,9 +822,11 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
copy = av_memdup(avctx, sizeof(*avctx));
if (!copy)
return AVERROR(ENOMEM);
+ copy->internal = NULL;
copy->priv_data = NULL;
copy->decoded_side_data = NULL;
copy->nb_decoded_side_data = 0;
+ copy->ch_layout = (AVChannelLayout){ 0 };
/* From now on, this PerThreadContext will be cleaned up by
* ff_frame_thread_free in case of errors. */
@@ -832,6 +835,10 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
p->parent = fctx;
p->avctx = copy;
+ err = av_channel_layout_copy(©->ch_layout, &avctx->ch_layout);
+ if (err < 0)
+ return err;
+
copy->internal = ff_decode_internal_alloc();
if (!copy->internal)
return AVERROR(ENOMEM);