Repository navigation
Conversation
…ture_pool_init
The combined assignment
VmafGpuPicturePool *const p = *pool = malloc(sizeof(*p));
in vmaf_gpu_picture_pool_init() publishes the pool pointer to the
caller's `*pool` argument *before* any later failure path runs. On
`goto free_p` (pic-array malloc failure or pthread_mutex_init failure)
the function then frees `p` while `*pool` still holds the dangling
pointer. The CUDA call site (`libvmaf.c:326`,
`return vmaf_gpu_picture_pool_init(&vmaf->cuda.ring_buffer, ...)`)
stores that handle directly in the long-lived
`VmafContext.cuda.ring_buffer`, and the natural `vmaf_close()`
teardown calls `vmaf_gpu_picture_pool_close(vmaf->cuda.ring_buffer)`
on the freed object — use-after-free, with double-free as a follow-on
once `close()` reaches its trailing `free(pool)`.
Fix: clear `*pool = NULL` at every failure label
* after the `if (!p)` malloc check (where the assignment already
stored NULL but we set it explicitly so the contract is grep-able);
* after `free(p)` at the `free_p` label, before falling through to
the shared `fail:` return.
The `fail:` label itself is unchanged. The contract this pins is
"caller may inspect `*pool` only on success; a non-zero return
guarantees `*pool == NULL`".
Adds a CPU-only regression test (`test_gpu_picture_pool_uaf`,
`suite=fast`) that triggers the `goto free_p` arm via an oversized
`pic_cnt` so the second `malloc()` returns NULL, then asserts that
the caller's handle is NULL on return. Verified locally that with
the fix reverted the test fails with the expected
"pool handle must be NULL after init failure (UAF regression)"
assertion, and with the fix in place all 50 fast-suite tests pass.
Documents the pattern in `core/src/AGENTS.md` as invariant #10 so
future out-parameter init functions in this directory inherit the
clear-on-failure contract by convention.
**Research digest**: [x] no research digest needed: small targeted
bug fix per CLAUDE.md §12 r11 ("trivial deliverable" sentinel).
Root cause + fix are inline in the commit body and the AGENTS.md
invariant note.
**Decision matrix**: [x] no alternatives: only-one-way fix.
Clearing `*pool = NULL` at the failure labels is the minimal
correctness-preserving change. Hoisting the assignment to the
success tail was considered but rejected because it changes the
emission shape of the const-init pattern that several reviewers
rely on for grep-ability.
**AGENTS.md invariant note**: `core/src/AGENTS.md` #10 added —
"Out-parameter init functions must clear the caller's handle on
every failure path" with `vmaf_gpu_picture_pool_init` as the
exemplar and a pointer to the regression test.
**Reproducer / smoke-test command**:
`meson setup build-cpu core -Denable_cuda=false -Denable_sycl=false
-Denable_hip=false && ninja -C build-cpu &&
meson test -C build-cpu test_gpu_picture_pool_uaf`.
Without the fix the test fails on the
"pool handle must be NULL after init failure (UAF regression)"
assertion; with the fix it passes in <1 ms.
**CHANGELOG fragment**:
`changelog.d/fixed/gpu-picture-pool-uaf-init-failure.md`.
**Rebase note**:
`docs/rebase-notes.md` — `gpu-picture-pool-uaf-on-init-failure`
entry added. The file is fork-added by ADR-0239; upstream still
ships the equivalent code as `cuda/ring_buffer.c` so any upstream
parallel fix won't textually conflict.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
22 tasks done
lusoris
marked this pull request as ready for review
May 31, 2026 13:22
lusoris
marked this pull request as draft
May 31, 2026 13:54
lusoris
marked this pull request as ready for review
May 31, 2026 13:59
Contributor
Author
|
Closing as part of marathon cleanup 2026-05-31 (150 PRs merged today). Content likely superseded by sibling merges. Reopen if specific finding still needs work; bigger PRs preferred going forward per session feedback. |
Contributor
Author
|
Superseded by #515 — bundled into one PR per bigger-PRs guidance. All three diffs preserved verbatim. |
lusoris
added a commit
that referenced
this pull request
Jun 2, 2026
…ool UAF/leak + #187 feature-dict double-free) - GPU pool UAF: clear *pool on every init() failure path so callers can't double-free a dangling pointer in vmaf_gpu_picture_pool_close() (ADR-0778). - picture_pool prealloc leak: two-pass approach — allocate all pictures first, then strip priv/ref; error unwind uses vmaf_picture_unref on intact pictures instead of manual aligned_free on already-detached data (ADR-0778 Fix-E). - feature-dict double-free: move feature-dictionary ownership into feature_collector; extractors no longer free dicts they don't own (ADR-0806). Rebased onto master (aa17751) — resolved add/add conflicts in .github/workflows/ by keeping the core/ path refs from master. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lusoris
added a commit
that referenced
this pull request
Jun 2, 2026
…ool UAF/leak + #187 feature-dict double-free) (#515) - GPU pool UAF: clear *pool on every init() failure path so callers can't double-free a dangling pointer in vmaf_gpu_picture_pool_close() (ADR-0778). - picture_pool prealloc leak: two-pass approach — allocate all pictures first, then strip priv/ref; error unwind uses vmaf_picture_unref on intact pictures instead of manual aligned_free on already-detached data (ADR-0778 Fix-E). - feature-dict double-free: move feature-dictionary ownership into feature_collector; extractors no longer free dicts they don't own (ADR-0806). Rebased onto master (aa17751) — resolved add/add conflicts in .github/workflows/ by keeping the core/ path refs from master. Co-authored-by: Lusoris <lusoris@pm.me> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
vmaf_gpu_picture_pool_init()(core/src/gpu_picture_pool.c) where the combined assignmentVmafGpuPicturePool *const p = *pool = malloc(...)publishes the pool pointer to the caller's*poolbefore any later failure path runs. Ongoto free_pthe function freespwhile*poolstill holds the dangling pointer; the CUDA call site (libvmaf.c:326) stores that handle in the long-livedVmafContext.cuda.ring_buffer, andvmaf_close()then callsvmaf_gpu_picture_pool_close()on the freed object — UAF + potential double-free.*pool = NULLafter the!pmalloc check and afterfree(p)at thefree_plabel. Thefail:label is unchanged.test_gpu_picture_pool_uafregression insuite=fastthat exercises thegoto free_parm by passing apic_cntlarge enough to make the secondmalloc()return NULL, then asserts*pool == NULL.core/src/AGENTS.md(chore(deps): Update rocm/rocm-terminal Docker tag to v6.4 #10) so future out-parameter init functions inherit the clear-on-failure contract by convention.Test plan
meson setup build-cpu core -Denable_cuda=false -Denable_sycl=false -Denable_hip=falseninja -C build-cpu— greenmeson test -C build-cpu test_gpu_picture_pool_uaf --print-errorlogs— passmeson test -C build-cpu --suite=fast— 50/50 pass*pool = NULLafterfree(p)reverted, the new test fails on the"pool handle must be NULL after init failure (UAF regression)"assertion. With the fix in place it passes in <1 ms.clang-tidy -p build-cpu core/src/gpu_picture_pool.c core/test/test_gpu_picture_pool_uaf.c— cleanclang-format --dry-run --Werroron touched C files — cleanready-for-review).ADR-0108 deep-dive deliverables
Research digest: [x] no research digest needed: small targeted bug fix per CLAUDE.md §12 r11 ("trivial deliverable" sentinel). Root cause + fix + the surrounding ring-buffer call site are explained inline in the commit body and pinned as
core/src/AGENTS.mdinvariant #10.Decision matrix: [x] no alternatives: only-one-way fix. Clearing
*pool = NULLat the failure labels is the minimal correctness-preserving change. Hoisting the*pool = ...assignment to the success tail was considered but rejected — it changes the emission shape of the const-init pattern reviewers grep for, and would still need a separate NULL-init for the early failure case.AGENTS.md invariant note:
core/src/AGENTS.mdinvariant #10 added — "Out-parameter init functions must clear the caller's handle on every failure path." Namesvmaf_gpu_picture_pool_initas the exemplar and points to the regression test.Reproducer / smoke-test command:
meson setup build-cpu core -Denable_cuda=false -Denable_sycl=false -Denable_hip=false ninja -C build-cpu meson test -C build-cpu test_gpu_picture_pool_uaf --print-errorlogsWithout the fix the test fails on the
"pool handle must be NULL after init failure (UAF regression)"assertion. With the fix it passes in microseconds.CHANGELOG fragment:
changelog.d/fixed/gpu-picture-pool-uaf-init-failure.md(per ADR-0221).Rebase note:
docs/rebase-notes.md—gpu-picture-pool-uaf-on-init-failure (2026-05-30)entry added. The filecore/src/gpu_picture_pool.cis fork-added by ADR-0239 (promotion of upstream'scuda/ring_buffer.cinto a backend-agnostic helper); upstream Netflix/vmaf still ships the originalcuda/ring_buffer.c, so any upstream parallel fix will land in a different TU and won't textually conflict.docs/state.mdupdated under "Recently closed" with theT-GPU-PICTURE-POOL-UAF-INIT-FAILURE-2026-05-30row per CLAUDE.md §12 r13.🤖 Generated with Claude Code