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]
