PR #25513 opened by Marti2203 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25513 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25513.patch
`unpack_intraframe()` and `decode_interframe_v4a()` reject a back-reference run when `offset + count` (for v4a, `offset + width + count`) is `>=` width*height. The same check is applied to `writeoffset`. The copy loops only touch indices up to that sum minus one, so a run that ends exactly on the last pixel of the frame is valid, but it gets rejected. Decoding of the packet stops with "Attempting to write out of bounds", but the error is not propagated and the frame is still returned. The end of the frame keeps stale pixels from an earlier frame. The patch changes the four checks to `>`, which matches the checks in `decode_interframe_v4()`. The intraframe read check is never the deciding one, because intraframe back-references always point backwards. I changed it too so the checks stay consistent. The literal-byte and tag 1 checks in the same functions were already correct and are not touched. Verification (master 38c6f36f93, release and ASan builds): - A synthetic 640x150 HNM4A file (3 frames, 3475 bytes) has a v4a inter frame and an intra frame whose last run ends exactly at width*height. Before the fix, the decoder logs the error twice, returns 0 and outputs frames with stale tails: 80 pixels wrong in frame 2 and 69 in frame 3. After the fix, it logs nothing and the tails are decoded correctly (frame 2 tail = the referenced rows, frame 3 tail = the run's colour). Both builds are ASan-clean before and after. - No FATE test covers hnm4 today. The new `fate-hnm4-boundary-runs` (test diff in the comment below; it needs a sample upload, so it is not in this branch yet) fails without the fix and passes with it. It needs the attached sample uploaded as `hnm4/boundary-runs.hnm`. The existing qdm2/vmnc tests I ran as a sanity check pass unchanged. This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually. 🤖 Generated with [Claude Code](https://claude.com/claude-code) From 564ceb202c050496b424f934c586ec4dd5ad1412 Mon Sep 17 00:00:00 2001 From: Martin Mirchev <[email protected]> Date: Tue, 27 Oct 2026 10:40:15 +0800 Subject: [PATCH] avcodec/hnm4video: fix off-by-one in back-reference bounds checks The back-reference copies in unpack_intraframe() and decode_interframe_v4a() access at most index offset + count - 1 (offset + width + count - 1 for v4a), and likewise for writeoffset, so a run is in bounds as long as that sum does not exceed width * height. The checks used >= instead and rejected a run that ends exactly on the last pixel of the frame. Decoding of the packet then stops with an "out of bounds" error, but the frame is still returned, so the end of the frame keeps the stale pixels of a previous frame. Use > as decode_interframe_v4() already does. The intraframe read check is never the decisive one, since intraframe back-references always point backwards, but is changed as well for consistency. Signed-off-by: Martin Mirchev <[email protected]> --- libavcodec/hnm4video.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c index 51e75789d2a..02e343fff5a 100644 --- a/libavcodec/hnm4video.c +++ b/libavcodec/hnm4video.c @@ -100,10 +100,10 @@ static void unpack_intraframe(AVCodecContext *avctx, const uint8_t *src, } count += 2; offset += writeoffset; - if (offset < 0 || offset + count >= hnm->width * hnm->height) { + if (offset < 0 || offset + count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; - } else if (writeoffset + count >= hnm->width * hnm->height) { + } else if (writeoffset + count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n"); break; @@ -326,10 +326,10 @@ static void decode_interframe_v4a(AVCodecContext *avctx, const uint8_t *src, offset -= 0x10000; } - if (offset + hnm->width + count >= hnm->width * hnm->height) { + if (offset + hnm->width + count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; - } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) { + } else if (writeoffset + hnm->width + count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n"); break; } -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
