Skip to content

Fix int32 overflow in permute_bwd_kernel row offsets - #172

Open
truong-v wants to merge 1 commit into
DeepLink-org:mainfrom
truong-v:fix/permute-bwd-int64-offsets
Open

Fix int32 overflow in permute_bwd_kernel row offsets#172
truong-v wants to merge 1 commit into
DeepLink-org:mainfrom
truong-v:fix/permute-bwd-int64-offsets

Conversation

@truong-v

@truong-v truong-v commented Aug 5, 2026

Copy link
Copy Markdown

Description

permute_bwd_kernel loads perm_row from the int32 inv_idx table and multiplies it by num_cols in 32-bit arithmetic; the product is widened to 64-bit only afterwards, so once perm_row * num_cols reaches 2^31 the offset wraps negative and the kernel reads far below the gradient buffer. The store address (pid_m * num_cols) wraps the same way at num_topK-times-larger row counts. With hidden = 7168 and topK = 8 the read wrap is reached at ~37.4k tokens: moe_permute_topk_bwd_op crashes with an illegal memory access (or silently returns garbage if the wrapped address is mapped).

Changes:

Measured on an L40S: at tokens=38000, topK=8, hidden=7168 (bf16, 304000-row buffer, 4.4 GB) the op crashes with an illegal memory access before this PR and completes after it, with sampled output rows bit-identical to a reference computed in the kernel's accumulation order. Overhead of the 64-bit addressing, full-op do_bench at tokens=8192, topK=8, hidden=7168 (no wrap, interleaved runs x3): 1.5663–1.5672 ms before, 1.5702–1.5706 ms after (~+0.2%).

Tests

tests/kernels/permute/ has no pytest coverage (its scripts are a standalone harness with a hard-coded device). Added tests/kernels/test_moe_permute_bwd.py: two small exact-correctness tests for moe_permute_topk_bwd_op against a reference with the kernel's accumulation order, plus test_moe_permute_topk_bwd_large_offsets, which drives a >2^31-element gradient buffer (skipped on GPUs with <10 GB memory). Reverting the kernel change alone makes the large-offsets test fail with the illegal memory access while the small tests still pass; all three pass with the fix.

Fixes #171

Environment

  • based on DLBlas main @ 9b5b362
  • NVIDIA L40S, driver CUDA 12.4
  • torch 2.6.0+cu124, triton 3.2.0, Python 3.12

perm_row is loaded as int32 and multiplied by num_cols in 32-bit
arithmetic; the product is widened to 64-bit only afterwards, so once
perm_row * num_cols reaches 2**31 the offset wraps negative and the
kernel reads far below the gradient buffer. The store address
(pid_m * num_cols) wraps the same way at larger row counts. At
hidden=7168, topK=8 the read wrap is reached at ~37.4k tokens.

Widen the program id and the loaded row index to int64 before any
scaling.
@CLAassistant

CLAassistant commented Aug 5, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

permute_bwd_kernel: int32 row-offset overflow, illegal memory access on large MoE gradient buffers

2 participants