Skip to content

fix(ffmpeg-patches): libvmaf_sycl filter — free sycl_state on close + NULL-guard QSV chain - #1067

Merged
lusoris merged 1 commit into
masterfrom
fix/round4-ffmpeg-patches
Jun 28, 2026
Merged

lusoris merged 1 commit into
masterfrom
fix/round4-ffmpeg-patches

Conversation

@lusoris

@lusoris lusoris commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Two verified defects from the adversarial round-4 audit in the dedicated libvmaf_sycl FFmpeg filter added by ffmpeg-patches/0005.

sev fix
high sycl_state leak — uninit_sycl called vmaf_close() but never vmaf_sycl_state_free(). vmaf_close() explicitly does not free the SYCL state (ownership isn't transferred), so the state + its USM allocations leaked on every filter close. Freed explicitly now; false comment removed.
med QSV NULL deref — do_vmaf_sycl walked the QSV zero-copy chain (data[3] → mfxFrameSurface1* → Data.MemId → mfxHDLPair* → ->first) with no NULL guards; a software-fallback QSV surface (no VA backing) crashed it. All three links NULL-checked → AVERROR(EINVAL) + diagnostic.

Deferred: finding #21 (a redundant but idempotent check_pkg_config libvmaf_sycl configure probe) is intentionally left — removing the wrong one risks breaking SYCL detection for no correctness gain.

Reproducer / verification

# Full series replay against the pinned base (CLAUDE rule #14):
git -C /path/to/ffmpeg-8 reset --hard n8.1.1 && git -C ffmpeg-8 clean -fdq
while read p; do p="${p%%#*}"; [ -z "${p// }" ] && continue; \
  git -C ffmpeg-8 apply --3way "ffmpeg-patches/$p" || break; done < ffmpeg-patches/series.txt
# → all 16 patches apply CLEAN (verified)

The patch was regenerated surgically — only the two + blocks in the vf_libvmaf.c hunk + the hunk-header recount (335→353); the configure/Makefile/allfilters hunks are byte-unchanged (a full format-patch/am --3way regeneration was rejected because it fuzzed the configure probe >= 3.0.0→2.0.0).

Deep-dive deliverables (ADR-0108)

  • Research digest — no digest needed: audit-derived bug-fix (audit in .workingdir2/BUGHUNT_2026-06-27.md).
  • Decision matrix — no alternatives: free-after-close + NULL-guard are the only correct fixes; feat(meta): VMAFX Phase 4b distributed platform umbrella ADR #21 deferred with rationale.
  • AGENTS.md invariant — the "keep these two + blocks; regenerate surgically not via format-patch" invariant is in this PR's docs/rebase-notes.md entry.
  • Reproducer — series-replay command above.
  • Changelog fragment — changelog.d/fixed/round4-ffmpeg-patches-audit.md.
  • Rebase-notes entry — docs/rebase-notes.md.

state.md / golden / patch-stack rule

  • docs/state.md — T-ROUND4-FFMPEG-PATCHES-2026-06-27 Recently-closed row.
  • CLAUDE rule feat(meta): VMAFX Phase 4 language-modernization foundation #14 satisfied — series-replay against n8.1.1 is CLEAN (16/16 patches).
  • Netflix golden unaffected (ffmpeg integration patch, not the metric path).
  • No new user surface. no docs needed: bug fix in an existing ffmpeg filter patch, no user-visible delta.

🤖 Generated with Claude Code

… NULL-guard QSV chain

Two verified defects from the adversarial round-4 audit, in the dedicated
libvmaf_sycl filter added by ffmpeg-patches/0005.

- sycl_state leak (high): uninit_sycl called vmaf_close() but never
  vmaf_sycl_state_free(). vmaf_close() explicitly does NOT free the SYCL state
  (ownership is not transferred), so the state + its USM allocations leaked on
  every filter close. Now freed explicitly after vmaf_close(); the false
  "vmaf_close handles it" comment is removed.
- QSV NULL deref (med): do_vmaf_sycl walked the QSV zero-copy handle chain
  (AVFrame->data[3] -> mfxFrameSurface1* -> Data.MemId -> mfxHDLPair* ->
  ->first) with no NULL guards; a software-fallback QSV surface with no VA
  backing crashed the filter. All three chain links are now NULL-checked,
  returning AVERROR(EINVAL) with a clear diagnostic.

The patch was regenerated surgically (only these two + blocks in the
vf_libvmaf.c hunk + the hunk-header recount 335->353; the configure/Makefile/
allfilters hunks are byte-unchanged). Verified by a full 16-patch
`git apply --3way` series replay against n8.1.1 (CLAUDE rule #14).

Finding #21 (a redundant but idempotent `check_pkg_config libvmaf_sycl`
configure probe) is intentionally left: the probe is idempotent and removing
the wrong one risks breaking SYCL detection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lusoris
lusoris merged commit 5756df9 into master Jun 28, 2026
59 of 68 checks passed
@lusoris
lusoris deleted the fix/round4-ffmpeg-patches branch June 28, 2026 00:24
@lusoris lusoris added this to the 1.0.0 — First release milestone Sep 4, 2026
lusoris added a commit that referenced this pull request Sep 26, 2026
Commit 384d97d / PR #1067 clobbered enable_chroma and plane clamping in
core/src/feature/metal/integer_psnr_metal.mm while reconciling repository
layout (BUG-048). This broke PSNR option parity across GPU backends:
- integer_psnr_metal rejected enable_chroma=false with -EINVAL.
- On monochrome YUV400P inputs, the extractor unconditionally dispatched
  and collected 3 planes, triggering out-of-bounds reads and spurious
  psnr_cb and psnr_cr sub-scores.

Restore enable_chroma (default true) and clamp n_planes to 1 for
VMAF_PIX_FMT_YUV400P or !enable_chroma. Modularize initialization helper
functions (psnr_metal_plane_geometry and alloc_readback_buffers) to adhere
to NASA JPL Rule 4 complexity limits (HISS-04).

Add device-free contract test test_gpu_psnr_option_parity_contract.py
asserting GPU option schema and plane clamping parity across CUDA, SYCL, HIP,
and Metal. Add unit tests in test_metal_kernel_registration.c and
test_metal_integer_psnr_parity.c.

ADR: docs/adr/1322-metal-integer-psnr-enable-chroma-parity.md
Signed-off-by: Lusoris <lusoris@pm.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant