This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 501d8eb62dd4f91dd19fb874f555db7ca3fde317
Author:     Michael Niedermayer <[email protected]>
AuthorDate: Sun Jul 5 01:38:19 2026 +0200
Commit:     michaelni <[email protected]>
CommitDate: Sat Jul 11 21:53:00 2026 +0000

    avcodec/bsf/dts2pts: chain same-gop nodes instead of collecting into a 
fixed array
    
    hevc_queue_frame() collected all tree nodes of the current gop into a
    fixed nodes[HEVC_MAX_DPB_SIZE * 2] array and asserted the count stayed
    within it. For a crafted HEVC stream the tree can hold slightly more
    same-gop nodes than that estimate (observed 34 vs 32), tripping the
    av_assert0 and aborting. Link the matching nodes into a list through a
    next pointer in the node instead; this has no size limit and needs
    neither extra passes nor allocation.
    
    Fixes: assertion failure
    Fixes: 
519466146/clusterfuzz-testcase-minimized-ffmpeg_BSF_DTS2PTS_fuzzer-5238235193475072
    Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
    
    Co-Authored-By: Fable-5
---
 libavcodec/bsf/dts2pts.c | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c
index b620c3f837..de44eaaedd 100644
--- a/libavcodec/bsf/dts2pts.c
+++ b/libavcodec/bsf/dts2pts.c
@@ -46,6 +46,7 @@ typedef struct DTS2PTSNode {
     int64_t duration;
     int          poc;
     int          gop;
+    struct DTS2PTSNode *next; // valid only during same-gop re-keying
 } DTS2PTSNode;
 
 typedef struct DTS2PTSFrame {
@@ -415,9 +416,7 @@ static int hevc_init_nb_frame(AVBSFContext *ctx, int poc)
 
 typedef struct DTS2PTSCollect {
     int gop;
-    DTS2PTSNode **out;
-    int count;
-    int max;
+    DTS2PTSNode *head, *tail;
 } DTS2PTSCollect;
 
 static int collect_same_gop(void *opaque, void *elem)
@@ -425,9 +424,12 @@ static int collect_same_gop(void *opaque, void *elem)
     DTS2PTSCollect *c = opaque;
     DTS2PTSNode *node = elem;
     if (node->gop == c->gop) {
-        if (c->count < c->max)
-            c->out[c->count] = node;
-        c->count++;
+        if (c->tail)
+            c->tail->next = node;
+        else
+            c->head = node;
+        c->tail = node;
+        node->next = NULL;
     }
     return 0;
 }
@@ -454,22 +456,26 @@ static int hevc_queue_frame(AVBSFContext *ctx, AVPacket 
*pkt, int poc, bool *que
 
     if (poc < s->nb_frame && hevc->gop == s->gop) {
         int dec = s->nb_frame - poc;
-        DTS2PTSNode *nodes[HEVC_MAX_DPB_SIZE * 2];
-        DTS2PTSCollect c = { s->gop, nodes, 0, FF_ARRAY_ELEMS(nodes) };
+        DTS2PTSCollect c = { s->gop, NULL, NULL };
 
         s->nb_frame -= dec;
 
+        // Crafted streams can exceed any DPB-based estimate of the node count,
+        // so chain the matching nodes through their next pointers instead of
+        // collecting them into a fixed size array. The chain is in ascending
+        // poc order; processing it in this order keeps the new keys collision
+        // free as any potential collision partner is re-keyed first.
         av_tree_enumerate(s->root, &c, NULL, collect_same_gop);
-        av_assert0(c.count <= c.max);
-        for (int i = 0; i < c.count; i++) {
+        while (c.head) {
             struct AVTreeNode *tnode = NULL;
-            DTS2PTSNode *r;
-            av_tree_insert(&s->root, nodes[i], cmp_insert, &tnode);
-            nodes[i]->poc -= dec;
-            r = av_tree_insert(&s->root, nodes[i], cmp_insert, &tnode);
-            if (r && r != nodes[i]) {
-                *r = *nodes[i];
-                av_refstruct_unref(&nodes[i]);
+            DTS2PTSNode *node = c.head, *r;
+            c.head = node->next;
+            av_tree_insert(&s->root, node, cmp_insert, &tnode);
+            node->poc -= dec;
+            r = av_tree_insert(&s->root, node, cmp_insert, &tnode);
+            if (r && r != node) {
+                *r = *node;
+                av_refstruct_unref(&node);
                 av_free(tnode);
             }
         }

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

Reply via email to