Skip to content

Validate SparseAttention CSR indices and key lengths element values - #29242

Merged
yuslepukhin merged 7 commits into
mainfrom
yuslepukhin/validate_sparse_attention
Jun 26, 2026
Merged

Validate SparseAttention CSR indices and key lengths element values#29242
yuslepukhin merged 7 commits into
mainfrom
yuslepukhin/validate_sparse_attention

Conversation

@yuslepukhin

@yuslepukhin yuslepukhin commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces device-side and host-side validation for sparse attention input indices and key sequence lengths, improving error detection and robustness for both CPU and CUDA implementations. It also adds an environment variable to optionally disable the new device-side validation for performance reasons. Some related test code has been updated to match these changes.

Validation improvements:

  • Added host-side validation functions (ValidateCSRIndices, ValidateKeyLengths) for CSR indices and key sequence lengths in the CPU kernel, and integrated them into the compute path. This ensures invalid inputs are caught early on the CPU. [1] [2]
  • Implemented a CUDA kernel (ValidateCSRIndicesKernel) and supporting function (ValidateCSRIndicesOnDevice) to check CSR row-pointer monotonicity, column-index range, and key lengths on device, with detailed error codes and messages. The CUDA kernel is invoked in the compute path unless disabled by environment variable. [1] [2] [3]

Configurability:

  • Introduced the environment variable ORT_DISABLE_SPARSE_ATTENTION_INPUT_VALIDATION to allow users to skip device-side validation for performance when inputs are known to be valid. This is parsed and used in the CUDA kernel. [1] [2] [3]

Test updates:

  • Refactored test helper function names and test input shapes to match the new validation logic and error messages. [1] [2] [3]

Other:

  • Removed redundant key length value checks from CheckInputs in favor of the new validation routines.

CheckInputs only validated tensor shapes for block_row_indices and
block_col_indices but never checked element values. This allowed
attacker-controlled values to be used as array indices in
ComputeAttentionProbs, leading to out-of-bounds memory access.

Add ValidateCSRIndices and ValidateKeyLengths for CPU EP that check:
- CSR row-pointer monotonicity and bounds
- Column indices within [0, max_blocks)
- Key lengths within valid range

Add ValidateCSRIndicesOnDevice for CUDA EP that performs equivalent
validation on-device using a single-warp kernel with strided iteration
and a scratch buffer error flag.

Add unit tests covering invalid CSR row pointers, non-monotonic values,
out-of-range column indices, negative values, and large OOB values.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens input validation for the SparseAttention contrib op by adding explicit CSR (block mask) and key-length element checks on both CPU and CUDA paths, aiming to prevent out-of-bounds access and improve robustness when inputs are malformed.

Changes:

  • Added CPU-side validators for CSR indices and key_total_sequence_lengths element ranges, and wired them into the CPU compute path.
  • Added a CUDA device validation kernel + host helper, invoked prior to the CUDA kernel execution.
  • Added new unit tests to ensure malformed CSR indices are rejected.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
onnxruntime/test/contrib_ops/sparse_attention_op_test.cc Adds negative tests for CSR element-value validation failures.
onnxruntime/contrib_ops/cuda/sparse/sparse_attention.cc Calls new device-side validation before CUDA kernel execution.
onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.h Declares CSR validation error codes and device validation entrypoint.
onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu Implements CUDA validation kernel + host wrapper.
onnxruntime/contrib_ops/cpu/sparse/sparse_attention.cc Invokes new CPU-side CSR + key-length validation helpers.
onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h Refactors key-length value checks and adds new CPU validators.

Comment thread onnxruntime/contrib_ops/cpu/sparse/sparse_attention_helper.h Outdated
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu Outdated
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu Outdated
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
Comment thread onnxruntime/test/contrib_ops/sparse_attention_op_test.cc Outdated
Dmitri Smirnov added 2 commits June 23, 2026 16:48
- Move ValidateCSRIndices and ValidateKeyLengths from header to
  anonymous namespace in sparse_attention.cc (not shared across TUs).
- Change Tensor pointer parameters to const Tensor& references since
  they are required (never null).
- Extend CUDA ValidateCSRIndicesOnDevice kernel to also validate
  seqlens_k_total (key lengths) in the same launch.
- Add CSRValidationError enum for device kernel error codes.
- Use full warp (32 threads) with strided iteration in the kernel.
- Scope scratch buffer allocation to validation call site.
…lper

- Only validate block_col_indices entries in [0, nnz) where nnz is the
  last row pointer value r[max_blocks], since entries beyond that are
  padding and not consumed by the kernel.
- Replace atomicExch with atomicCAS to preserve the first detected
  error code deterministically across concurrent threads/blocks.
- Mark RunSparseAttentionCSRValidationTest as static to avoid external
  linkage.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention.cc Outdated

@tianleiwu tianleiwu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One new finding on the device-side validation (the CPU path and the previously raised CUDA points look good). Also worth noting as a positive: moving the key-length value check out of the shared CheckInputs fixes a latent bug — CheckInputs used to dereference total_key_lengths->Data<int32_t>() on the host, which on the CUDA path is a device pointer (UB). That read is now correctly done on device.

Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
- Fix existing key-length tests to use valid CSR indices (col_count=4).
- Rename RunSparseAttentionInvalidInputTest to
  RunSparseAttentionInvalidKeyLengthsTest.
- Fix CUDA kernel race: thread 0 validates row pointers sequentially,
  then __syncthreads ensures r[max_blocks] is safe before all threads
  cooperate on col-index validation.
- Update kernel comment to reflect actual thread cooperation model.
- Make error message layout-agnostic for kCSRValidationRowFirstNotZero.
- Add tests: multi-layout invalid col/row in second layout, invalid
  col within NNZ range, padding acceptance beyond NNZ.
@yuslepukhin
yuslepukhin force-pushed the yuslepukhin/validate_sparse_attention branch from 1c97efb to af1f999 Compare June 24, 2026 18:54
@yuslepukhin
yuslepukhin requested review from Copilot and tianleiwu June 24, 2026 18:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread onnxruntime/contrib_ops/cuda/sparse/sparse_attention_impl.cu
Comment thread onnxruntime/test/contrib_ops/sparse_attention_op_test.cc
- Add ORT_DISABLE_SPARSE_ATTENTION_INPUT_VALIDATION env var to skip
  device-side CSR and key-length validation when inputs are known to
  be well-formed (addresses @tianleiwu latency concern).
- Add CUDA-specific validation tests under #ifdef USE_CUDA that use
  head_size=128, sparse_block_size=64, MLFloat16 (CUDA EP requirements).
  Tests cover: row first element, row monotonicity, col OOB, col large
  value, and key length OOB. Tests run only with DefaultCudaExecutionProvider.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread onnxruntime/test/contrib_ops/sparse_attention_op_test.cc
SparseAttention requires past/present to share buffers (in-place).
OpTester allocates separate buffers, causing pointer equality check
to fail before reaching compute. The padding non-rejection behavior
is already implicitly verified by RejectsBlockColIndicesInvalidWithinNNZ.
@yuslepukhin
yuslepukhin force-pushed the yuslepukhin/validate_sparse_attention branch from 31f4a40 to bbde0f8 Compare June 24, 2026 20:28
@yuslepukhin
yuslepukhin requested a review from Copilot June 24, 2026 20:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread onnxruntime/test/contrib_ops/sparse_attention_op_test.cc Outdated
- Move ValidateCSRIndicesOnDevice call to right after CheckInputs,
  before the past/present shared-buffer enforcement. The validation
  only reads input tensors (CSR indices, key lengths) and does not
  need the KV cache buffers. This allows OpTester-based CUDA tests
  to exercise validation without IOBinding.
- Fix test comment: ORT_MAKE_STATUS returns Status, does not throw.
- Document in CUDA test helper why OpTester works without shared
  buffers (validation runs before the buffer check).
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.

3 participants