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]

Reply via email to