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

# Summary
`mov_flush_fragment()` dereferences a NULL mov->mdat_buf when an MP4 trailer is 
written before any packet was muxed. This crashes every fragmented mode that 
defers the initial moov to the first flush (including hybrid_fragmented).

Regression in >= 8.1 from 
[627da1111c9d](https://code.ffmpeg.org/FFmpeg/FFmpeg/commit/627da1111c9d8ebf8a3a190a164cd502b99a09cb).

Reproduction: this command segfaults
`ffmpeg -f lavfi -i color=s=64x64 -frames:v 0 -movflags +frag_keyframe out.mp4`

# Tests
Ran on macOS / arm64, tested on booth 8.1 and the newly 9. versions.
- fate passes
- clean exit 0 (no segfaults) from previous reproduction command after the patch
- Regular non-empty outputs are byte-identical.


>From cc2f0c9a3585d0574919523eb7042ecb50e7a6c6 Mon Sep 17 00:00:00 2001
From: Ackanir <[email protected]>
Date: Mon, 17 Aug 2026 14:36:53 +0200
Subject: [PATCH] avformat/movenc: fix crash when flushing a fragment with no
 data

mov_flush_fragment() calls ffio_reset_dyn_buf() on mov->mdat_buf when
writing the initial moov. That buffer is allocated lazily on the first
packet, so it is still NULL when the trailer is written before anything
was muxed, and ffio_reset_dyn_buf() dereferences it.

627da1111c9d replaced ffio_free_dyn_buf(), which tolerates NULL, with
ffio_reset_dyn_buf(), which does not, turning this case into a crash.

This affects every fragmented mode that defers the initial moov to the
first flush.

Skip the block entirely when the buffer was never opened. Nothing
references the empty mdat it would otherwise write, as no samples were
muxed.

Reproduced with:
ffmpeg -f lavfi -i color=s=64x64 -frames:v 0 -movflags +frag_keyframe out.mp4

Fixes: 627da1111c9d ("libavformat/movenc: Uses dynamic buffers for fragmented 
chunks")
Signed-off-by: Ackanir <[email protected]>
---
 libavformat/movenc.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 2a3226c70f..f87e12096e 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -6790,11 +6790,13 @@ static int mov_flush_fragment(AVFormatContext *s, int 
force)
             return 0;
         }
 
-        buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
-        avio_wb32(s->pb, buf_size + 8);
-        ffio_wfourcc(s->pb, "mdat");
-        avio_write(s->pb, buf, buf_size);
-        ffio_reset_dyn_buf(mov->mdat_buf);
+        if (mov->mdat_buf) {
+            buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
+            avio_wb32(s->pb, buf_size + 8);
+            ffio_wfourcc(s->pb, "mdat");
+            avio_write(s->pb, buf, buf_size);
+            ffio_reset_dyn_buf(mov->mdat_buf);
+        }
 
         if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
             mov->reserved_header_pos = avio_tell(s->pb);
-- 
2.52.0

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

Reply via email to