[Kernel] Resurrect rotted gather-cache OOB test + defensive block-table bound-checks - #45393
waynehacking8 wants to merge 3 commits into
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
This pull request has merge conflicts that must be resolved before it can be |
Two OOB reads in csrc/libtorch_stable/cache_kernels.cu: - gather_and_maybe_dequant_cache: block_table_id derived from the in-batch offset plus seq_starts was never bounded against the block table width, so seq_starts combinations read past the row (vllm-project#45380). The kernel now receives block_table.size(1) and skips out-of-range tokens. This also resurrects the vllm-project#27909 regression test, which had rotted: it still called the op without the (since-added) token_to_seq argument and failed with a binding TypeError on current main. - cp_gather_and_upconvert_fp8_kv_cache: the binary search clamps req_id to 0, so a nonzero workspace_starts[0] makes token_offset negative and underflows the block table read (block_table[-1], vllm-project#45377). The kernel now returns early for negative offsets. Validated with a standalone index-logic replica under compute-sanitizer on SM120: pre-fix logic reports 4161 invalid global reads across the two reporters' trigger cases; with the guards, 0 errors on both the triggers and valid inputs (the guards never trip on valid input by construction). Fixes vllm-project#45380 Fixes vllm-project#45377 Co-authored-by: Claude Signed-off-by: Wayne Chiu <waynehacking8@gmail.com>
The regression test used workspace_starts=[4], giving token_offset=-4. CUDA integer division truncates toward zero, so cache_block_idx = -4/64 = 0 stays in bounds and the test passed on the *unfixed* kernel too -- providing no regression protection. Use [64] so flat_warp_id 0 -> token_offset -64 -> cache_block_idx -1 -> the block_table[-1] OOB read the fix guards against (observable under compute-sanitizer). Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Wayne Chiu <waynehacking8@gmail.com>
5936f96 to
10932b3
Compare
…ect#48642) Upstream vllm-project#48642 dropped the seq_lens parameter from cp_gather_and_upconvert_fp8_kv_cache (total_tokens now derives from dst.size(0)), which silently misaligned this test's positional args after rebase. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jer3fzhUR2bNKxM1Prqnsg Signed-off-by: waynehacking8 <waynehacking8@gmail.com>
|
Rebased on latest main to resolve the conflict with #48642:
cc @MatthewBonanni since this touches the same kernel as #48642 — PTAL. Could a maintainer add the |
|
This resolves #45377 but I don't think this PR is necessary. It's a defense against something that shouldn't happen in production. Also, as is, this just kind of kicks the can down the road because it lets the invalid rows stay uninitialized |
Purpose
Restore a dead regression test and add two defensive bound-checks in the CP gather cache kernels (
csrc/libtorch_stable/cache_kernels.cu).Resurrect a dead regression test (the substantive fix).
tests/kernels/test_cache_kernels.py::test_gather_cache_oob(the [Bug]: Potential Out-of-bounds in cache_kernels.cu #27909 sanitizer-mode regression test) still called the op without the since-addedtoken_to_seqargument and fails with a binding error on currentmain(Expected a value of type 'Tensor' for argument 'token_to_seq' but instead found type 'int'). The only sanitizer-mode coverage for this kernel family has been dead since the signature changed; updated to the current signature.Defensive bound-checks for two malformed-index paths ([Bug]: Out of bounds in gather_and_maybe_dequant_cache #45380, [Bug]: Out of bounds in cp_gather_and_upconvert_fp8_kv_cache #45377). Both kernels index
block_table[...]with a computed offset that isn't range-checked:gather_and_maybe_dequant_cache:block_table_idcan exceed the table width ifseq_startspushes a token past the block table's coverage ([Bug]: Out of bounds in gather_and_maybe_dequant_cache #45380). The kernel now receivesblock_table.size(1)andcontinues past out-of-range indices.cp_gather_and_upconvert_fp8_kv_cache: the ownership binary search floorsreq_idat 0, so a nonzeroworkspace_starts[0]would drivetoken_offsetnegative and underflow the read ([Bug]: Out of bounds in cp_gather_and_upconvert_fp8_kv_cache #45377). Early-return on a negative offset (warp-uniform).Reachability (honest): I could not establish that either input occurs in production. For [Bug]: Out of bounds in cp_gather_and_upconvert_fp8_kv_cache #45377 I traced the callers —
flashmla_sparse.pybuildsworkspace_startsaszeros()thencumsum()into[1:], with the per-chunk adjustment zeroing each chunk slice's first entry, soworkspace_starts[0] == 0always andtoken_offset >= 0by construction. For [Bug]: Out of bounds in gather_and_maybe_dequant_cache #45380 the chunked-context caller (mla_attention.py) sizes the block table to the full sequence, so a well-formed config keepsblock_table_idin range. The sanitizer evidence below is from feeding the issues' constructed inputs directly. So these are defensive guards against malformed indices intoblock_table, not fixes for demonstrated production failures — happy to drop either if you'd prefer not to guard a currently-unreachable path.Test Plan / Result
tests/kernels/test_cache_kernels.py—2 passed(previously1 failedonmainfrom the signature rot). Against the prebuilt binary these exercise the op bindings; CI's source build + sanitizer covers the guards.--tool memcheck, sm_120, CUDA 13.0) on a replica of the kernels' indexing logic (payload simplified to plain copies; the indexing under test preserved verbatim), fed the issues' constructed trigger inputs:The guards are pure bound checks, so behavior on well-formed input is unchanged.
Duplicate check
No open PR addresses either issue: searched
45380,45377,gather_and_maybe_dequant,cp_gather_and_upconvert; both issues have zero comments; reporter has no authored PRs; file history onmainshows no fix since the libtorch_stable migration. Related but distinct: #45384 fixes an int32 overflow inconcat_mla_qin the same file (different function; no textual overlap).AI assistance disclosure
Prepared with AI assistance (Claude); reviewed, compiled, and sanitizer-validated by the submitter.