PR #24863 opened by Forgejo_Fairy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24863 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24863.patch
## Summary `mov_read_trun()` reserves the complete run in the sample index before processing its entries. Its timestamp-overflow return can therefore leave uninitialized entries within the published range and skip the fragment-index adjustment. Check the timestamp before publishing the current sample, then break through the existing hole-compaction path. The change also keeps `stts_count` and conditional `ctts_count` synchronized with `nb_index_entries` and `tts_count` when a run is shortened. This preserves valid later-fragment entries that were moved aside for an insertion, unlike the count-clamping approach currently proposed in #22898. Fixes #24252. ## Validation - Reproduced the original zero-size trigger at 21bbd98e7b05 with the supplied sample and ASan's `0xbe` allocation fill. - Reproduced the remaining path on unmodified master 98e92563a3b with a generated fragment starting at DTS `INT64_MAX - 500`; the next demux call seeks to `0xbebebebebebebebe`. - With this change, the timestamp-overflow input retains only the valid earlier entries and never reads the poisoned range. - The supplied zero-size input continues to produce all 10 packets after e9dc8fd4d6c. - All MOV FATE targets enabled by a default build pass. - `git diff --check` passes. >From c4ab7db067bf94bd1eb816f68587a0a8a878e36b Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 3 Oct 2026 03:16:27 +0000 Subject: [PATCH] avformat/mov: clean up trun index on timestamp overflow Do not publish the sample whose duration would overflow DTS. Break out of the sample loop so the existing hole-compaction and fragment-index adjustment paths preserve any later entries already moved aside for this trun. Keep every sample-count marker in sync when compacting a short or invalid trun. Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/24252 Assisted-by: Fairy --- libavformat/mov.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index 71c4e38c88..690b83691b 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -6204,7 +6204,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) int64_t dts, pts = AV_NOPTS_VALUE; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; - int flags, distance, i; + int flags, distance, i, ret = 0; int64_t prev_dts = AV_NOPTS_VALUE; int next_frag_index = -1, index_entry_pos; size_t requested_size; @@ -6441,6 +6441,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) pts = AV_NOPTS_VALUE; } + if (av_sat_add64(dts, sample_duration) != dts + (uint64_t)sample_duration) { + ret = AVERROR_INVALIDDATA; + break; + } + keyframe = !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC | MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); @@ -6468,8 +6473,6 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) "size %u, distance %d, keyframe %d\n", st->index, index_entry_pos, offset, dts, sample_size, distance, keyframe); distance++; - if (av_sat_add64(dts, sample_duration) != dts + (uint64_t)sample_duration) - return AVERROR_INVALIDDATA; dts += sample_duration; offset += sample_size; sc->data_size += sample_size; @@ -6481,7 +6484,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->nb_frames_for_fps ++; } } - if (frag_stream_info) + if (!ret && frag_stream_info) frag_stream_info->next_trun_dts = dts + sc->time_offset; if (i < entries) { // EOF found before reading all entries. Fix the hole this would @@ -6498,6 +6501,9 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sti->nb_index_entries -= gap; sc->tts_count -= gap; + sc->stts_count -= gap; + if (flags & MOV_TRUN_SAMPLE_CTS) + sc->ctts_count -= gap; if (index_entry_pos < sc->current_sample) { sc->current_sample -= gap; } @@ -6522,6 +6528,9 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) fix_frag_index_entries(&c->frag_index, next_frag_index, frag->track_id, entries); + if (ret < 0) + return ret; + if (pb->eof_reached) { av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n"); return AVERROR_EOF; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
