[mpc] fix out-of-bounds output write in MPCcompress (issue #317) - #320
Conversation
The compressor sized the output buffer's residual region by the input word count (insize), but MPCcompress can emit up to one residual word per thread across all launched threads. Small inputs still transpose full 64-word bit-planes from the padded tail, so a tiny input (e.g. one word) makes the kernel write past d_out, which compute-sanitizer flags as an invalid __global__ write. Size the residual region to the worst case the kernel can emit: ceil(insize/TPB) chunks * TPB threads, plus the header and per-64 bitmap words. The device->host copy still uses the actual compressed length from the header, so output is unchanged and there is no perf impact. Applied to the cuda, hip, and sycl variants. Fixes #317 Co-authored-by: Cursor <cursoragent@cursor.com>
Fix has been confirmed: This PR: 64e1d71 has 0 errors. |
|
Thank you for the tests. |
There was a problem hiding this comment.
Pull request overview
Fixes MPC compression buffer overflows by allocating for worst-case per-thread residual output.
Changes:
- Computes chunk-rounded residual capacity.
- Applies the fix consistently across CUDA, HIP, and SYCL.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/mpc-cuda/main.cu |
Corrects CUDA output sizing. |
src/mpc-hip/main.cu |
Corrects HIP output sizing. |
src/mpc-sycl/main.cpp |
Corrects SYCL output sizing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
keitaTN
left a comment
There was a problem hiding this comment.
This fix looks reasonable to me when handling out-of-bound access for arrays whose size is not multiple of 64. BTW, it assume warp/wavefront/vector size is 64 or less (31,16,8,4,2, or 1)? Do you have any back-up plan for future architecture especially RISC-V that can accommodate bigger vector size? (At ORNL, we are thinking abou tobtaining Tenstorrent).
|
Thanks for the review, Keita. Short answer: the sizing fix itself carries no vector-width assumption — the 1. The 2. The residual term is a per-thread bound, so it is width-agnostic. 3. Where the width assumption actually is: the ballot that assembles the bitmap. unsigned int bitmap = __ballot_sync(0xffffffff, loc);
if (lanex == 32) sbuf2[tid] = bitmap;
__syncthreads();
if (lanex == 0) {
if (idx < n) compressed[1 + idx / 64] = (sbuf2[tid + 32] << 32) + bitmap;
}HIP and SYCL are templated on 4. Back-up plan for wider vectors. Two width-agnostic replacements, both local to the kernel:
|
Summary
Fixes #317 — a heap/global buffer overflow in the
MPCcompresskernel reported withcompute-sanitizeron a crafted small input.The compressor sized the output buffer's residual region by the input word count (
insize):but
MPCcompresscan emit up to one residual word per thread across all launched threads. Small inputs still transpose full 64-word bit-planes from the padded tail, so a tiny input (e.g. one 8-byte word → 24-byte buffer) makes the kernel write pastd_outatcompressed[start + tid], which the sanitizer flags as an invalid__global__write.Fix
Size the residual region to the worst case the kernel can emit —
ceil(insize/TPB)chunks ×TPBthreads — plus the header and per-64 bitmap words:This is the "size
d_outto the worst case the kernel can emit" option from the issue's suggested fix. The kernel is untouched, so there is no ABI change and no truncation of output.Applied to the
mpc-cuda,mpc-hip, andmpc-syclvariants.Notes
output[0] >> 32), so program output is unchanged.argc == 3) is affected; decompression is unchanged.Test plan
0xAA…, maximizing bit-plane residuals) — now completes cleanly.mpc-cudawith-lineinfoand re-runcompute-sanitizer --tool=memcheck ./main ./mpc-memcheck.txt 1to confirm no invalid writes (no CUDA toolchain on my machine).