Skip to content

[Spec] Fix fa3 EAGLE draft-decode expand page_table scatter OOB for topk>1 + page_size>1#27360

Merged
hnyls2002 merged 6 commits into
mainfrom
lsyin/fix-fa3-spec-expand-oob
Jun 6, 2026
Merged

[Spec] Fix fa3 EAGLE draft-decode expand page_table scatter OOB for topk>1 + page_size>1#27360
hnyls2002 merged 6 commits into
mainfrom
lsyin/fix-fa3-spec-expand-oob

Conversation

@hnyls2002

@hnyls2002 hnyls2002 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

FlashAttentionMultiStepBackend builds the EAGLE draft-decode expand metadata via draft_decode_set_expand_metadata, which scatters compacted page indices into a step-tight (decode_length + 1)-column page_table. The page_size > 1 branch scattered the full num_steps-wide cache_loc instead of slicing it to decode_length (the page_size == 1 branch already slices). So for topk > 1 the per-branch draft slots span more distinct pages than the row holds, and scatter_ writes out of bounds — silently corrupting the cuda-graph pool and surfacing later as an illegal memory access / NaN logits.

Fix: slice cache_loc[:, :decode_length] at the (non-compiled) cuda-graph metadata call site, matching the page_size == 1 path, so the scatter fills at most decode_length of the decode_length + 1 columns. An always-on size assert (cache_loc.shape[1] <= page_table columns) right before the scatter makes any future regression fail fast at the source instead of silently corrupting memory — no env flag, no torch.compile graph break.

Repro

Standalone repro (real spec server, EAGLE3 topk=8 + page_size=2 + fa3): https://gist.github.com/hnyls2002/909e761ff0c7b67b824a88e59b198874

page_size=2 makes one branch's contiguous draft slots span more distinct pages than the decode_length + 1 row, so a single request trips the first draft-decode step.

  • With this PR: passes all rounds.
  • SGLANG_DEBUG_REVERT_PR=27360 python repro_fa3_draft_expand_page_table_overflow.py reverse-applies the fix; the always-on assert then fires deterministically: AssertionError: draft expand page_table too narrow: cache_loc width 5 > 2 columns (decode_length + 1); page_size=2, topk=8, num_steps=5.
cd test/ && python3 registered/spec/eagle/test_spec_eagle_fa3.py
cd test/ && python3 registered/spec/eagle/test_spec_eagle_stress.py

CI States

Latest PR Test (Base): 🚫 Run #27055762654
Latest PR Test (Extra): ✅ Run #27055762627

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request prevents out-of-bounds writes in the draft-decode page table scatter by slicing cache_loc to the active decode_length. It also introduces an optional async assertion (_ASSERT_DRAFT_EXPAND_OOB) to guard against out-of-bounds errors. The reviewer pointed out that if positions is empty (e.g., during empty batches), calling .max() on it will raise a runtime error, and suggested using torch.nn.functional.pad to safely handle empty tensors without causing graph breaks under torch.compile.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread python/sglang/srt/layers/attention/flashattention_backend.py Outdated
@hnyls2002

Copy link
Copy Markdown
Collaborator Author

/rerun-test test_self_e2e_pd_perturb.py

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Results for /rerun-test test_self_e2e_pd_perturb.py:

🚀 2-gpu-h100 (1 test): ✅ View workflow run

cd test/ && python3 registered/kv_canary/test_self_e2e_pd_perturb.py

@hnyls2002
hnyls2002 merged commit 26b9053 into main Jun 6, 2026
76 of 132 checks passed
@hnyls2002
hnyls2002 deleted the lsyin/fix-fa3-spec-expand-oob branch June 6, 2026 07:24
hnyls2002 added a commit to Zhiy-Zhang/sglang that referenced this pull request Jun 8, 2026
ch-wan added a commit that referenced this pull request Jun 13, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ch-wan added a commit that referenced this pull request Jun 14, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ch-wan added a commit that referenced this pull request Jun 20, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ch-wan added a commit that referenced this pull request Jun 20, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ch-wan added a commit that referenced this pull request Jun 20, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ch-wan added a commit that referenced this pull request Jun 20, 2026
_apply_cuda_graph_metadata has no callers since init_forward_metadata_out_graph
converged onto the use_bound seam (its body was inlined verbatim as the
use_bound=True path of _compute_forward_metadata). Pure deletion.

Repoint the debug-only PR #27360 revert toggle (SGLANG_DEBUG_REVERT_PR, never
active in normal runs) from the removed _apply_cuda_graph_metadata to
_compute_forward_metadata, where the matched `cache_loc = cache_loc[:, :decode_length]`
line now lives unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant