Fixes: o7gcsAIJJTmP/testcase/dovi_pps_overflow.c
Fixes: o7gcsAIJJTmP
Fixes: signed integer overflow
Signed integer overflow Replicated through API with UBSAN
Found during the review of PR 25408.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Fixes: EMtBgkYsAzTJ/testcase/dovi_ext_overflow.c
Fixes: EMtBgkYsAzTJ
Fixes: out of array write
Out of array write Replicated through API with ASAN
Found during the review of PR 25408.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
ff_cbs_lcevc_list_add() resolves a position of -1 to the end of the
list, but the block was then set up at blocks[-1].
Fixes: Am7oZsN0qfFR/testcase/cbs_lcevc_append.c
Fixes: Am7oZsN0qfFR
Fixes: out of array write
Out of array write Replicated through API with ASAN
Found during the review of PR 25408.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Fixes: u1TxsBfg36kp/testcase/two_b.mp4 / gen_au.py gen_mp4.py
Fixes: u1TxsBfg36kp
Fixes: AISLE-2026-0150-00084
Fixes: assertion failure
Assertion failure Replicated through UnModified FFmpeg
Found-by: Joshua Rogers (AISLE)
The report suggested returning the NAL unit together with the found
block and inserting into its list, and replacing the assertion by a
runtime check.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
AISLE-2026-0150-00875 describes the same overlapping entries amplified
further by av_exif_ifd_to_dict(), which formats the values bounded here.
Fixes: 7ReYNupbuA78/testcase/evil.tiff / gen.py
Fixes: 7ReYNupbuA78
Fixes: AISLE-2026-0150-00031
Fixes: memory exhaustion
Memory exhaustion Replicated through UnModified FFmpeg with ASAN
Found-by: Joshua Rogers (AISLE)
The report suggested a cumulative allocation budget per EXIF buffer.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Fixes: TPu5aVjgBh7t/testcase/crafted.hevc
Fixes: TPu5aVjgBh7t
Fixes: AISLE-2026-0150-00819
Fixes: division by zero
Division by zero Replicated through UnModified FFmpeg with UBSAN
Found-by: Joshua Rogers (AISLE)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
The CLUT seed is built from every region that may be drawn, so it is
the same for every image of a caption, but it was rebuilt for each one.
Build it once instead. Converting an image only appends colors past the
seed and never changes the alpha table, so restoring the CLUT size at
the start of each image restores the seed.
The output is unchanged: the encoded bitmaps of both aribcaption FATE
samples are identical, with and without ignore_ruby.
Reported-by: Forgejo_Fairy
Reference: #24992
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
Text mode output is caption.text, which never holds ruby. It decided
whether there was anything to show from region_count, so a caption with
only ruby regions was output as text. Without CS, that event held an
empty text and erased the previous caption, which only CS may do. With
CS it failed: libaribcaption returns a NULL text when it is empty, and
av_strdup(NULL) was reported as ENOMEM.
Decide on the regions that are not ruby and hold a character instead.
The text itself is not a reliable test, as it can hold line breaks
without any character. Nothing to show gives no event, or the empty
clear event with CS, as in the other modes; a NULL text is taken as
empty.
Add a text mode test on the ruby sample. The ruby only caption without
CS at 5s now produces no event.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
ARIBCC_RENDER_STATUS_NO_IMAGE leaves the render result empty, so it
reaches the same "no image" check as a GOT_IMAGE result without images.
Let it fall through instead of keeping a second copy of the clear
handling, and log the image count before the result is cleaned up,
which reset it to 0.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
The bitmap CLUT seed, the single rect position and the ass loop each
tested "ruby with ignore_ruby" on their own. Use one helper so they
always agree on which regions are left out. It also leaves out regions
without any character, which would otherwise produce an event holding
only tags.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
clut_alpha holds the alpha values pixels are snapped to, but only its
first entry was reset for each rect; the others kept the values seeded
by earlier captions. Those stayed available for quantization even when
the current seed palette has no such alpha, so pixels could snap to a
stale alpha, e.g. to 128 instead of 255 after an earlier caption with a
semi-transparent color. Reset all entries with the CLUT.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
In multi rect mode each region position is made non-negative by adding
the plane size when it is negative. Single rect mode instead took the
minimum of the raw positions, then fixed only y. A negative x, or a mix
of negative and non-negative y, put the single rect elsewhere than the
regions it holds. Normalize each region position first, as multi rect
mode does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
A caption without regions and a caption whose regions were all skipped
as ruby both end up with nothing to show, and were handled by two
copies of the same clear-screen check. With no region the loop writes
nothing, so the later check already covers it. Drop the early return.
Also clean up through the fail path if adding the clear rect fails,
like every other error in this function, instead of leaving the
partially built subtitle to the caller.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
The new sample sub/aribcaption_ruby.ts (1316 bytes, synthetic) is an
ARIB STD-B24 profile A caption stream. Small size (SSZ) text is decoded
as a ruby region. Caption glyphs are one DRCS pattern and ruby is an
alphanumeric character that is never drawn with ignore_ruby, so the
results do not depend on installed fonts:
t=2s CS + caption
t=3s CS + ruby only
t=4s CS + ruby line above a caption line
t=5s ruby only, without CS
With ignore_ruby=1, only CS clears, ruby is not drawn, and a caption
that is all skipped ruby without CS produces no event:
bitmap: 2s 1 rect, 3s clear, 4s 1 rect (the one caption line)
ass, multi rect: 2s, 3s clear, 4s
ass, single rect: same events, checked with the dialogue text so the
4s position comes from the caption line, not the
skipped ruby above it
Before the fixes in this series, the bitmap test overflows the rects
array at 4s, the multi rect ass test misses the 3s clear, and the single
rect ass test has an extra 5s event and the ruby position.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
With ass_single_rect=1 and ignore_ruby=1, a caption whose regions are
all ruby still produced one event holding only the position tags, even
without a clear screen (CS). Track whether any region was written and
treat "none" like the multi rect mode: emit nothing, or the empty clear
event if the caption carries CS.
The line separator was also appended after every region but the last
one, so skipping a trailing ruby region left a dangling "{\r}\N". Write
it before every written region but the first instead. Output is
unchanged when no region is skipped.
The position of the single rect was also taken from all regions,
including skipped ruby above the text. Ignore skipped regions there too.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
The ass error path freed sub->rects[0] .. [region_count - 1], but
ff_ass_add_rect() grows the array one rect at a time and counts the
rects it added in sub->num_rects, including one whose dialog string
failed to allocate. Entries past num_rects are not initialized, so an
allocation failure part way through read them, or past the array.
Free up to sub->num_rects instead.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
Reported-by: Forgejo_Fairy
Reference: #24992
Found-by: Joshua Rogers <joshua.rogers@aisle.com>
The bitmap path allocated one rect per rendered image but filled them,
freed them and placed them by looping over the caption regions. The
renderer does not draw every region: with ignore_ruby it drops ruby
regions, and it always drops regions that are too small to draw. A
caption with one ordinary and one ruby region then wrote past the end
of the rects array.
Loop over the images instead. The renderer does not say which region an
image comes from, so the CLUT can no longer be seeded from "its" region.
Seed it from the colors of every region that may be drawn; colors that
are not seeded are still added from the image itself, as before.
While at it, use bounded insertion for every CLUT seed color,
including the text and background colors added in the character loop.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
Reported-by: Forgejo_Fairy
Reference: #24992
With ignore_ruby=1 and ass_single_rect=0, a caption whose regions are all
ruby skips every region and returned no event, even when it carries a
clear screen (CS). The previous caption then stayed on screen. The bitmap
path and ass_single_rect=1 already erase it in that case.
Emit the empty clear event in that case too.
Such captions do occur in broadcasts: among 2293 captions from 40 recent
Japanese TV recordings, 3 carried CS with only ruby regions. With this
change, ignore_ruby=1 output gains exactly those 3 clear events, and
output with the default options is unchanged for all 40 recordings.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
The clear path ignored the return value of ff_ass_add_rect() and
reported an event even if adding the empty rect failed, unlike the other
two calls in this function. Return the error instead; the caller frees
the partially built subtitle.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
The text and ass paths treated every caption without regions as a clear
and emitted an empty ("") subtitle. A statement containing only TIME
also decodes to zero regions, without the clear-screen flag, so it
erased the caption that was being displayed.
Test ARIBCC_CAPTIONFLAGS_CLEARSCREEN as the bitmap path already does,
and emit nothing for other regionless captions.
Add text and ass mode tests on the existing aribcaption_clear.ts sample
(visible caption, TIME-only statement, CS-only statement). Each
reference has two events; before this change there was a third, empty
one for the TIME-only statement.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
aribcaption_trans_text_subtitle() always fills exactly one rect, but
allocated the rects array with ctx->caption.region_count entries. For a
caption without regions, such as a clear screen, that is a zero-sized
allocation, and writing sub->rects[0] goes past its end.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
Found-by: Joshua Rogers <joshua.rogers@aisle.com>
aribcc_renderer_render() fills ctx->render_result with images that are
owned by the caller and must be released with
aribcc_render_result_cleanup(). The bitmap path did this only for the
"unchanged", "no image" and unknown-status returns. After converting the
images into AVSubtitleRects, and on the error path, the result was left
allocated, and the next call overwrote it without freeing it. Every
rendered caption therefore leaked its bitmaps.
The images are not used after conversion, so release them before
returning from both paths.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdDiDRusmi6eD7qSrKBjHb
Reported-by: Forgejo_Fairy
Reference: #24067
parse_psfile() advances buf and decrements size while reading the
file, and then passed these to av_file_unmap() instead of what
av_file_map() returned. With mmap, munmap() then fails with EINVAL
because the pointer is no longer page aligned, so the mapping leaks on
every init and every psfile command; on builds without mmap, av_free()
is called on a pointer into the middle of the buffer.
Keep the mapped pointer and size and unmap those.
Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
Send next while the final segment is active and compare all output frames. This covers rejection without truncating the remaining segment, using generated sources and no external samples.
Assisted-by: Fairy
process_command() called flush_segment() without checking that there is a
next segment. On the last segment this moved cur_idx past the inputs while
the outputs still wanted frames, so activate() accessed cat->in[] and
ctx->inputs[] out of bounds and crashed, e.g.
ffmpeg -f lavfi -i "testsrc2=d=0.2[a];testsrc2=d=1[b];[a][b]concat=n=2,sendcmd=c='0.3 concat next'" -f null -
Fail the command instead.
Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
Fixes: Ju3bQZ3z2paC
Fixes: AISLE-2026-0150-00166
Fixes: memory leak
Memory leak Replicated through UnModified FFmpeg with ASAN (AVI with one
268435475 byte WVC1 packet holding a single slice start code)
Found-by: Joshua Rogers (AISLE)
Fixes: ZiiTReozL7KE
Fixes: AISLE-2026-0150-00435
Fixes: deadlock
Deadlock Replicated through UnModified FFmpeg with timeout (AVI with a
268435476 byte Mimic intra frame followed by inter frames; ffmpeg with
frame threading never exits)
Found-by: Joshua Rogers (AISLE)
Fixes: 1ivYPVLs04AI
Fixes: AISLE-2026-0150-00896
Fixes: use of uninitialized memory
Use of uninitialized memory Replicated through UnModified FFmpeg with MSAN
(CFHD AVI sample with the ImageHeight tag raised from 720 to 1080)
Found-by: Joshua Rogers (AISLE)
Fixes: 4dmaFsb0C0KW
Fixes: AISLE-2026-0150-00882
Fixes: use of uninitialized memory
Use of uninitialized memory Replicated through UnModified FFmpeg with MSAN
Found-by: Joshua Rogers (AISLE)
A vignette is applied to the test source and reversed with both
transforms, the PSNR against the source is compared with a tolerance.
Assisted-by: Claude
A level works in place on the lowpass lattice of the previous one, so
the mode needs 5 planes instead of 9 + 3 * levels and about an order of
magnitude less computation. Shrinkage is less effective without the
shift invariance of the undecimated transform.
Assisted-by: Claude
Every pass over a plane, the row and column passes of the transforms as
well as the box filters and the per coefficient operations of the
shrinkage, is split into slices of lines. The output does not depend on
the number of threads.
Assisted-by: Claude
Lowpass coefficients are stored at even and highpass ones at odd
positions of the line, so a level works in place on the lattice of the
previous level's lowpass coefficients. Reconstruction from a single
polyphase set needs no averaging, hence no factor 0.5.
Assisted-by: Claude
Dividing by the attenuation amplifies the noise and the quantization
steps of the dark areas by the same factor. The wavelet mode performs
the division in the pixel domain, then transforms the result and its
per pixel noise variance, propagated through the squared filter taps as
if the samples were uncorrelated, with the undecimated 9/7 wavelet.
Each detail coefficient is Wiener shrunk toward 0 with a signal
variance estimated from a 7x7 box of coefficients at the dilation of
the level, weighted by their precision and counted only when it exceeds
the noise by 3 standard errors of independent coefficients. The lowpass
of the top level averages over large areas and is kept, so the shade of
heavily attenuated areas survives.
Assisted-by: Claude
Makes the transform usable by other filters. The analysis filter taps become
a parameter so the same code can also propagate variances with squared taps.
Assisted-by: Claude
The size and checksum of the encoded file pin the slice layout and the
remap coding of a 704x576 float frame, which the 360x288 default slice
limit splits into 2x2 slices.
The escape code of a Golomb-Rice residual is 12 + bits long and
put_bits() writes at most 31 bits, so bits must stay below 20. The RCT
planes of remapped 32bit floats need log2 of the summed remap counts of
two planes, which a slice of at most 1<<18 pixels keeps within 19 bits.
The default slice size of 360x288 is within that, larger slices requested
with -slices were written with escape codes longer than put_bits()
supports. The assertion on k follows the same limit.
The testcases reproduce since b0c77e5a12.
Fixes: out of array read
Fixes: fAak9zecyttL/testcase/poc.vvc
Fixes: fAak9zecyttL/testcase/poc-entry-points.vvc
Fixes: fAak9zecyttL
Found-by: mzfr <security@mzfr.me>
Fixes: heap-use-after-free
Fixes: YtyT0QH1InrQ
Fixes: ANT-2026-13DK7NZD
Fixes: poc.264
Found-by: Claude and Ada Logics
Use after free Replicated through UnModified FFmpeg with ASAN
Fixes: negative-size-param
Fixes: assertion failure
Fixes: wzomtdUBffdP
Fixes: ANT-2026-G2YFQ5N2
Fixes: poc.exr
Found-by: Claude and Ada Logics
Negative size memcpy and assertion failure Replicated through UnModified FFmpeg with ASAN
Fixes: heap-buffer-overflow (read)
Fixes: BIqbuSbTJqAH
Fixes: ANT-2026-V2EPGE9M
Fixes: poc.avi
Found-by: Claude and Ada Logics
Out of array read Replicated through UnModified FFmpeg with ASAN
Fixes: heap-buffer-overflow (write)
Fixes: GITTfi6VsK4u
Fixes: ANT-2026-5KX1BXM6
Fixes: poc.flv
Found-by: Claude and Ada Logics
Out of array write Replicated through UnModified FFmpeg with ASAN