1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

avcodec/vp8: do not await a negative reference-frame row

vp8_mc_luma()/vp8_mc_chroma() derive the reference row to await from y_off,
which includes the block's motion vector, and never floor it at 0, so a vector
pointing above the frame makes the awaited row negative.

For a 16x16 block the expression still bottoms out at 0 for any vector inside
clamp_mv()'s +-16 px margin, which is why the omission is easy to miss. The
split modes, however, predict 8- and 4-row blocks, where a much smaller vector
suffices: at mb_y 0 with block_h 8, y_off -12 gives (3 - 12 + 8) >> 4 == -1,
and with block_h 4, y_off -8 does. SPLITMV sub-vectors are moreover never
clamped, and NEWMV deltas are applied after clamp_mv(), so larger vectors are
reachable too.

ff_thread_progress_await() returns as soon as progress >= n, and progress is
initialised to -1 under frame threading, so a negative row is treated as
already reached and no happens-before edge with the thread decoding the
reference frame is established. emulated_edge_mc() nevertheless clamps the
source rectangle and reads row 0 of the reference plane, i.e. the row is read
without waiting for it to be written.

Floor the awaited row at 0, the lowest row the subsequent read can touch. The
floor only ever raises a negative row to 0, never above a row already awaited
on the same frame, so it cannot introduce a stall.

Fixes: unsynchronized cross-thread read of reference frame rows
Fixes: IFu1maPxsZFJ
Found-by: Mozilla's AI bot, reviewed and reported by Chun-Min Chang <cchang@mozilla.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Chun-Min Chang
2026-07-28 17:49:35 -07:00
committed by michaelni
parent a024f8c541
commit b772f5033c

View File

@@ -1848,7 +1848,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst,
y_off += mv->y >> 2;
// edge emulation
ff_progress_frame_await(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 4);
ff_progress_frame_await(ref, FFMAX((3 + y_off + block_h + subpel_idx[2][my]) >> 4, 0));
src += y_off * linesize + x_off;
if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] ||
y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) {
@@ -1906,7 +1906,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
// edge emulation
src1 += y_off * linesize + x_off;
src2 += y_off * linesize + x_off;
ff_progress_frame_await(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 3);
ff_progress_frame_await(ref, FFMAX((3 + y_off + block_h + subpel_idx[2][my]) >> 3, 0));
if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] ||
y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) {
s->vdsp.emulated_edge_mc(td->edge_emu_buffer,