PR #25015 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25015
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25015.patch

This is the first batch of fixes for (pre existing) issues found in reviews



>From 8c72121b3e4d89c3817c99693b53eb3f516789ac Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:15:19 +0200
Subject: [PATCH 01/13] avcodec/hevc: keep the active VPS when a layer SPS is
 cleared

set_sps(s, l, NULL) drops the SPS of a non-base layer whose VPS does not
match the active one. It also dropped the active VPS of the base layer,
the next base layer frame then dereferenced the NULL VPS in
ff_hevc_is_alpha_video().

Fixes: NULL pointer dereference
Fixes: 4WKa0bETBVfE
Regression since: c7f0753a6b
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24895
NULL pointer dereference Replicated through UnModified FFmpeg with ASAN
---
 libavcodec/hevc/hevcdec.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
index a36ea57bc2..d5e0fa06d3 100644
--- a/libavcodec/hevc/hevcdec.c
+++ b/libavcodec/hevc/hevcdec.c
@@ -764,11 +764,12 @@ static int set_sps(HEVCContext *s, HEVCLayerContext *l, 
const HEVCSPS *sps)
 
     pic_arrays_free(l);
     av_refstruct_unref(&l->sps);
-    av_refstruct_unref(&s->vps);
 
     if (!sps)
         return 0;
 
+    av_refstruct_unref(&s->vps);
+
     ret = pic_arrays_init(l, sps);
     if (ret < 0)
         goto fail;
-- 
2.52.0


>From 15d4e20f2387547e975c7ca0b8128ce4cbf81100 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:19:20 +0200
Subject: [PATCH 02/13] avcodec/aac/aacdec_usac: do not store the custom
 channel layout in the output configuration

OutputConfiguration is copied by value between oc[0] and oc[1]. A custom
channel layout built from bsOutputChannelPos that cannot be retyped to a
native layout owns a heap allocated map, the copies alias it and it is
freed twice.

The layout only reaches avctx->ch_layout and is replaced by the one derived
from the elements when the configuration is parsed completely.

Fixes: double free
Fixes: Qn47KDJBCeGk
Regression since: eee5fa0808
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
Double free Replicated through UnModified FFmpeg with ASAN
---
 libavcodec/aac/aacdec_usac.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c
index 7a34cf63d3..3587c76c07 100644
--- a/libavcodec/aac/aacdec_usac.c
+++ b/libavcodec/aac/aacdec_usac.c
@@ -625,24 +625,22 @@ int ff_aac_usac_config_decode(AACDecContext *ac, 
AVCodecContext *avctx,
         if (nb_channels > 64)
             return AVERROR(EINVAL);
 
-        av_channel_layout_uninit(&ac->oc[1].ch_layout);
+        AVChannelLayout ch_layout = { 0 };
 
-        ret = av_channel_layout_custom_init(&ac->oc[1].ch_layout, nb_channels);
+        ret = av_channel_layout_custom_init(&ch_layout, nb_channels);
         if (ret < 0)
             return ret;
 
         for (int i = 0; i < nb_channels; i++) {
-            AVChannelCustom *cm = &ac->oc[1].ch_layout.u.map[i];
+            AVChannelCustom *cm = &ch_layout.u.map[i];
             cm->id = usac_ch_pos_to_av[get_bits(gb, 5)]; /* bsOutputChannelPos 
*/
         }
 
-        ret = av_channel_layout_retype(&ac->oc[1].ch_layout,
-                                       AV_CHANNEL_ORDER_NATIVE,
+        ret = av_channel_layout_retype(&ch_layout, AV_CHANNEL_ORDER_NATIVE,
                                        
AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
-        if (ret < 0)
-            return ret;
-
-        ret = av_channel_layout_copy(&avctx->ch_layout, &ac->oc[1].ch_layout);
+        if (ret >= 0)
+            ret = av_channel_layout_copy(&avctx->ch_layout, &ch_layout);
+        av_channel_layout_uninit(&ch_layout);
         if (ret < 0)
             return ret;
     } else {
-- 
2.52.0


>From 8b4538075cfb131be56cecdd9f3ca882b4e8c9c3 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:19:20 +0200
Subject: [PATCH 03/13] avcodec/aac: do not overwrite avctx->ch_layout when
 restoring the output configuration

ff_aac_output_configure() copies the restored layout into avctx->ch_layout,
the plain assignment before it dropped whatever avctx->ch_layout owned.

This is hardening, no leak was replicated.
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
---
 libavcodec/aac/aacdec.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c
index fdebe139c3..66ab648016 100644
--- a/libavcodec/aac/aacdec.c
+++ b/libavcodec/aac/aacdec.c
@@ -472,7 +472,6 @@ static void pop_output_configuration(AACDecContext *ac)
     if (ac->oc[1].status != OC_LOCKED && ac->oc[0].status != OC_NONE) {
         copy_oc(&ac->oc[1], &ac->oc[0]);
 
-        ac->avctx->ch_layout = ac->oc[1].ch_layout;
         ff_aac_output_configure(ac, ac->oc[1].layout_map, 
ac->oc[1].layout_map_tags,
                                 ac->oc[1].status, 0);
     }
-- 
2.52.0


>From c5d4d4d09883d08d15f3639ca9a271222194dbd0 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:19:21 +0200
Subject: [PATCH 04/13] avcodec/aac/aacdec_usac: release the extension payload
 buffers before clearing the configuration

The buffers of fragmented extension payloads were lost when a new
configuration was parsed.

Fixes: memleak
Fixes: yxoDgZkJaJ4D
Regression since: eee5fa0808
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
Memleak Replicated through UnModified FFmpeg with ASAN
---
 libavcodec/aac/aacdec_usac.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c
index 3587c76c07..5c6d04226d 100644
--- a/libavcodec/aac/aacdec_usac.c
+++ b/libavcodec/aac/aacdec_usac.c
@@ -571,6 +571,8 @@ int ff_aac_usac_config_decode(AACDecContext *ac, 
AVCodecContext *avctx,
     if (!ac)
         return AVERROR_PATCHWELCOME;
 
+    for (int i = 0; i < usac->nb_elems; i++)
+        av_refstruct_unref(&usac->elems[i].ext.pl_buf);
     memset(usac, 0, sizeof(*usac));
     usac->loudness.input_method_val = -1;
 
-- 
2.52.0


>From aee421e722a8a3d3727b466c087556114e602c93 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:22:27 +0200
Subject: [PATCH 05/13] 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
---
 libavcodec/pthread_frame.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 5ec9a8a974..44b48875da 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);
     }
 
@@ -824,6 +825,7 @@ static av_cold int init_thread(PerThreadContext *p, int 
*threads_to_free,
     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 +834,10 @@ static av_cold int init_thread(PerThreadContext *p, int 
*threads_to_free,
     p->parent = fctx;
     p->avctx  = copy;
 
+    err = av_channel_layout_copy(&copy->ch_layout, &avctx->ch_layout);
+    if (err < 0)
+        return err;
+
     copy->internal = ff_decode_internal_alloc();
     if (!copy->internal)
         return AVERROR(ENOMEM);
-- 
2.52.0


>From 0365a2976b2be52bd95671244fbbb920ea6cd82d Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:24:05 +0200
Subject: [PATCH 06/13] avformat/libmodplug: return the error of a failed read
 instead of passing it to ModPlug_Load()

The negative result was used as the length of the never written buffer,
libmodplug converted it to an unsigned length and parsed the buffer with
that bound.

Fixes: use of uninitialized memory
Fixes: cIsMCH26EnE2
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24914
Use of uninitialized memory Replicated through UnModified FFmpeg with Valgrind
---
 libavformat/libmodplug.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavformat/libmodplug.c b/libavformat/libmodplug.c
index d9ab14b3bc..56a2c8b386 100644
--- a/libavformat/libmodplug.c
+++ b/libavformat/libmodplug.c
@@ -201,6 +201,8 @@ static int modplug_read_header(AVFormatContext *s)
     if (!modplug->buf)
         return AVERROR(ENOMEM);
     sz = avio_read(pb, modplug->buf, sz);
+    if (sz < 0)
+        return sz;
 
     ModPlug_GetSettings(&settings);
     settings.mChannels       = 2;
-- 
2.52.0


>From 0bc0d4f8d0bc528d8a210dd49561595c880d9498 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:31:13 +0200
Subject: [PATCH 07/13] avcodec/tdsc: reject unknown cursor formats before
 replacing the cursor sprite

The sprite buffer was reallocated and the new geometry stored before the
format was checked, the uninitialized sprite was then painted onto every
following frame.

Fixes: use of uninitialized memory
Fixes: JJihVQxE36RL
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24682
Use of uninitialized memory Replicated through UnModified FFmpeg with Valgrind
---
 libavcodec/tdsc.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c
index f31655ce3d..976b67b8f9 100644
--- a/libavcodec/tdsc.c
+++ b/libavcodec/tdsc.c
@@ -209,6 +209,11 @@ static int tdsc_load_cursor(AVCodecContext *avctx)
 
     cursor_fmt = bytestream2_get_le32(&ctx->gbc);
 
+    if (cursor_fmt != CUR_FMT_MONO && cursor_fmt != CUR_FMT_BGRA &&
+        cursor_fmt != CUR_FMT_RGBA) {
+        avpriv_request_sample(avctx, "Cursor format %08x", cursor_fmt);
+        return AVERROR_PATCHWELCOME;
+    }
     if (w < 1 || w > 256 || h < 1 || h > 256) {
         av_log(avctx, AV_LOG_ERROR, "Invalid cursor dimensions %dx%d.\n", w, 
h);
         return AVERROR_INVALIDDATA;
@@ -305,9 +310,6 @@ static int tdsc_load_cursor(AVCodecContext *avctx)
             }
         }
         break;
-    default:
-        avpriv_request_sample(avctx, "Cursor format %08x", cursor_fmt);
-        return AVERROR_PATCHWELCOME;
     }
 
     return 0;
-- 
2.52.0


>From f23e57d259de4a379efabb9af384a7a1df88e3ff Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:31:13 +0200
Subject: [PATCH 08/13] avcodec/sunrast: expand only the bytes of a packed line
 that were decoded

The 1 and 4 bit per pixel expansion read (w + 7 >> 3) * depth bytes per
line while only (depth * w + 7) >> 3 were written, for 4 bits per pixel
and widths that are not a multiple of 8 up to 3 uninitialized bytes per
line were expanded into the padding of the line.

Fixes: use of uninitialized memory
Fixes: mGcNxX6EOTeJ
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24877
Use of uninitialized memory Replicated through API with Valgrind
---
 libavcodec/sunrast.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/sunrast.c b/libavcodec/sunrast.c
index 1cd51f4637..fcab3de3b5 100644
--- a/libavcodec/sunrast.c
+++ b/libavcodec/sunrast.c
@@ -199,7 +199,7 @@ static int sunrast_decode_frame(AVCodecContext *avctx, 
AVFrame *p,
         uint8_t *ptr_free = ptr2;
         ptr = p->data[0];
         for (y=0; y<h; y++) {
-            for (x = 0; x < (w + 7 >> 3) * depth; x++) {
+            for (x = 0; x < len; x++) {
                 if (depth == 1) {
                     ptr[8*x]   = ptr2[x] >> 7;
                     ptr[8*x+1] = ptr2[x] >> 6 & 1;
-- 
2.52.0


>From c074239cdc0cda180a05488c12e113f8c93ff7ca Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:31:13 +0200
Subject: [PATCH 09/13] swscale: reject interlaced frames whose fields have no
 lines

A one line interlaced frame has an empty bottom field, when source and
destination format were equal the graph was still built for it and
divided by the zero slice height.

Fixes: division by zero
Fixes: 9FwqJRpgNJo3
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24851
Division by zero Replicated through UnModified FFmpeg with UBSAN
---
 libswscale/swscale.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index d224c3275b..070b0f5939 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1562,6 +1562,12 @@ int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, 
const AVFrame *src)
             goto fail;
         }
 
+        if (src_fmt.height <= 0 || dst_fmt.height <= 0) {
+            err_msg = "Interlaced frames need at least two lines";
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+
         src_ok = ff_test_fmt(backends, &src_fmt, 0);
         dst_ok = ff_test_fmt(backends, &dst_fmt, 1);
         if ((!src_ok || !dst_ok) && !ff_fmt_equal(&src_fmt, &dst_fmt)) {
-- 
2.52.0


>From 2e2d2e45df7984c925c34e7da0e5499ae3fb2498 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:31:13 +0200
Subject: [PATCH 10/13] avutil/imgutils: compute the line size of bitstream
 formats without overflow

Fixes: signed integer overflow
Fixes: P0BVJKDC5JLx
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24756
Signed integer overflow Replicated through UnModified FFmpeg with UBSAN
---
 libavutil/imgutils.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index 8ff8a6be41..1aa6ab0cd3 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -69,7 +69,7 @@ int image_get_linesize(int width, int plane,
     linesize = max_step * shifted_w;
 
     if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM)
-        linesize = (linesize + 7) >> 3;
+        linesize = (linesize >> 3) + !!(linesize & 7);
     return linesize;
 }
 
-- 
2.52.0


>From 0babfe27510d4b4390d7879b4b0596d69e4c8c5c Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:37:41 +0200
Subject: [PATCH 11/13] ffplay: round the chapter length without overflowing

A chapter length near INT64_MAX overflowed the rounding, the hour count
was also truncated to int.

Fixes: signed integer overflow
Fixes: 7JHyBJsQ7bNE
Regression since: 80a55704b7
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24589
Signed integer overflow Replicated through UnModified FFmpeg with UBSAN
---
 fftools/ffplay.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index c9369d6a72..bea5816089 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -1374,10 +1374,10 @@ static void chapter_list_script(VideoState *is, 
AVBPrint *script)
         av_bprintf(script, CHAPTER_LIST_EVENT "Hint,{\\an5\\pos(%d,%d)}i\n", 
l.detail_x, y + l.line / 2);
         if (row->length < 0)
             continue;
-        seconds = (row->length + AV_TIME_BASE / 2) / AV_TIME_BASE;
+        seconds = av_rescale_rnd(row->length, 1, AV_TIME_BASE, 
AV_ROUND_NEAR_INF);
         av_bprintf(script, CHAPTER_LIST_EVENT "%s,{\\an6\\pos(%d,%d)}", style, 
l.length_x, y + l.line / 2);
         if (seconds >= 3600)
-            av_bprintf(script, "%d:%02d:%02d\n", (int)(seconds / 3600), 
(int)(seconds / 60 % 60), (int)(seconds % 60));
+            av_bprintf(script, "%"PRId64":%02d:%02d\n", seconds / 3600, 
(int)(seconds / 60 % 60), (int)(seconds % 60));
         else
             av_bprintf(script, "%d:%02d\n", (int)(seconds / 60), (int)(seconds 
% 60));
     }
-- 
2.52.0


>From f7adeba059f9a8be00ac15781d625b5f79fa5398 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:39:11 +0200
Subject: [PATCH 12/13] avformat/flacdec: do not flush the parser on a zero
 length read in flac_read_timestamp()

A read that returns no data because the input reported EOF transiently
was passed to the parser as the EOF flush, the data of the next read was
then parsed by the flushed parser.

Fixes: NULL pointer dereference
Fixes: iEqlwpm7chzS
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24909
NULL pointer dereference Replicated through API with ASAN
---
 libavformat/flacdec.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index 8d907bdc30..12d4b7305f 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -311,6 +311,10 @@ av_unused static int64_t 
flac_read_timestamp(AVFormatContext *s, int stream_inde
 
         if (ret >= 0 || ret == AVERROR(EAGAIN))
             ret = ff_raw_read_partial_packet(s, pkt);
+        if (!ret) {
+            av_packet_unref(pkt);
+            continue;
+        }
         if (ret < 0){
             if (ret == AVERROR(EAGAIN))
                 continue;
-- 
2.52.0


>From b6600ee457565b82b32f0efdd03d37f491c53d22 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 11 Oct 2026 07:39:11 +0200
Subject: [PATCH 13/13] avformat/libcurl: fail a ranged request that delivered
 no data

A completed reply with a valid Content-Range but an empty body left the
request offset unchanged, so the identical request was sent again
without limit.

Fixes: endless request loop
Fixes: nnnKyLY2U5HN
Found during triage of the review of 
https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24607
Endless request loop Replicated through UnModified FFmpeg
---
 libavformat/libcurl.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libavformat/libcurl.c b/libavformat/libcurl.c
index 80c1f7a9fa..6f17d0ded3 100644
--- a/libavformat/libcurl.c
+++ b/libavformat/libcurl.c
@@ -769,6 +769,16 @@ static void on_done(CurlContext *c, CURLcode code)
         if (c->end_off > 0)
             file_end = FFMIN(file_end, c->end_off - 1);
         if (c->seekable && c->request_end >= 0 && c->request_end < file_end) {
+            if (!received) {
+                av_log(c->h, AV_LOG_ERROR, "Server sent back an empty reply "
+                       "for the range starting at %"PRId64"\n", 
c->request_start);
+                pthread_mutex_lock(&c->mutex);
+                c->loop->num_errors++;
+                update_status_locked(c, AVERROR(EIO), code);
+                pthread_cond_broadcast(&c->cond);
+                pthread_mutex_unlock(&c->mutex);
+                return;
+            }
             c->is_initial = 0;
             start_request(c);
             return;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to