Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request changes the type of lba_off from int to uint64_t in mooncake-store/src/transfer_task.cpp to prevent 32-bit integer overflow and pointer wrapping during large transfers. The review feedback recommends addressing potential mixed-sign arithmetic issues between the unsigned lba_count and signed remaining_lba by casting both operands to uint64_t and ensuring remaining_lba is non-negative.
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.
| uint64_t lba_off = | ||
| task->lba_count - task->remaining_lba; |
There was a problem hiding this comment.
The subtraction task->lba_count - task->remaining_lba performs mixed-sign arithmetic because lba_count is an unsigned 32-bit integer (uint32_t) while remaining_lba is a signed integer (int). If remaining_lba is negative (e.g., due to an unexpected state or overflow), it will be implicitly converted to a large unsigned value, leading to an incorrect lba_off due to underflow.\n\nTo prevent mixed-sign arithmetic issues and ensure defensive programming, consider casting both operands to uint64_t after ensuring remaining_lba is non-negative.
uint64_t lba_off =\n static_cast<uint64_t>(task->lba_count) -\n static_cast<uint64_t>(std::max(0, task->remaining_lba));|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
The red All 11 other build/test jobs on the same run passed ( |
… over 4 GiB The SPDK NoF worker computes the host buffer offset for each sub-I/O as `lba_off * block_size`, where lba_off was an int and block_size a uint32_t, so the product is evaluated in 32-bit unsigned arithmetic. Once the running offset reaches 4 GiB (lba_off * block_size >= 2^32) it wraps around and submit_ptr addresses the wrong part of the buffer: the DMA for the tail of a >4 GiB transfer then reads from / writes to the start of the user buffer instead, silently corrupting data. submit_lba two lines below is already widened to 64-bit, so only the host pointer offset was left narrow. A single SpdkNofTask carries lba_count = size / block_size for the whole request with no size cap, so any NoF transfer larger than 4 GiB reaches this path (the same >4 GiB scenario fixed for SSD offload in kvcache-ai#2570). Widen lba_off to uint64_t so the offset arithmetic stays 64-bit. Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
7fc0f07 to
f3a9bd0
Compare
|
Gentle nudge on this one — it's a small type fix ( |
|
Rebased a while back and it is still mergeable with a green CI. The overflow is reachable on 32-bit hosts writing SPDK NoF at offsets past 4 GiB, and the patch is contained to the offset arithmetic plus a regression test. Could someone take a look when there is a moment? |
|
One more nudge on this small one. Still mergeable and green; it keeps 32-bit hosts from wrapping the SPDK NoF host-pointer offset past 4 GiB by widening lba_off to uint64_t. Happy to rebase again if that helps it get a look. |
|
Re-checked against current main: the overflow is still there. |
|
Also still current four days on: merges cleanly (MERGEABLE on main) with green CI. The wrap is one line of arithmetic but the failure mode is ugly: |
|
Checked against current main: the code moved (now line 535) but the bug is unchanged, still This PR is still one line of arithmetic, still merges clean, CI still green. Happy to rebase or re-verify if that helps, otherwise a look when someone has a moment would be much appreciated. |
|
Still current on latest main; merged it in (1b6bbb0) so CI reruns on the fixed pipeline (#4513 restored the build, #4440 pinned the wheel-test torch). The one-line widening still applies at its new location (transfer_task.cpp:535), merge was clean. For the NoF side: the wrap is unchanged on main, |
|
Green across the board and alogfans approved the transfer-side read of this. Branch protection still wants a store codeowner pass, so a look from @ykwd @stmatengss @XucSh @YiXR when one of you has a minute would move it. The change is a single widening in transfer_task.cpp: lba_off computed in 32 bits wraps once a NoF transfer crosses 4 GiB, and submit_ptr then addresses the wrong part of the buffer. The branch is mergeable against current main; happy to refresh if anything drifts. |
|
Second ping, a week after the last one: this has been green and approved since 10-15 and nothing is waiting on my side. Happy to rebase if the merge queue needs it. |
|
Closing this as superseded by the NoF decoupling refactor (#3424), which removed the code path this PR fixes. The 32-bit wrap lived in Thanks to whoever picks up NoF hardening next; happy to re-open if a residual 32-bit path is spotted elsewhere. |
Description
In the SPDK NoF worker (
mooncake-store/src/transfer_task.cpp,SpdkNofWorkerPool::workerThread), the host buffer offset for each sub-I/O was computed as:block_sizeis auint32_t, solba_off * block_sizeis evaluated in 32-bit unsigned arithmetic. Once the running offset reaches 4 GiB (lba_off * block_size >= 2^32) the product wraps around andsubmit_ptrpoints to the wrong part of the buffer. The DMA for the tail of a >4 GiB transfer then reads from / writes to the start of the user buffer instead of the intended region, silently corrupting data.The device-side address one line below —
uint64_t submit_lba = task->lba + lba_off;— is already 64-bit, so only the host pointer offset was left narrow.This is reachable for any sufficiently large transfer: a single
SpdkNofTaskis created withlba_count = size / block_sizefor the whole request and there is no size cap at the submit site (submitNofTransferonly checks block alignment), solba_offwalks from 0 up tolba_countas the task drains. It is the same >4 GiB scenario that was fixed for SSD offload in #2570.The fix widens
lba_offtouint64_tso the offset arithmetic stays 64-bit, matching the already-widenedsubmit_lba.Module
mooncake-store)Type of Change
How Has This Been Tested?
The SPDK NoF path is behind
USE_NOFand needs SPDK + NVMe-oF hardware, so I could not build or exercise it locally (no native SPDK toolchain on this machine). It is verified three ways:Standalone reproduction of the arithmetic. Mirroring the exact types (
int lba_off,uint32_t block_size) and picking the firstlba_offwhose byte offset crosses 4 GiB for a 5 GiB transfer with 4096-byte blocks:The 32-bit expression wraps to 0 (off by exactly 4 GiB); the 64-bit expression is correct.
Parity with [Store] fix integer overflow in BatchOffload for objects larger than 4 GiB #2570, which fixed the same 32-bit-overflow-on-a->4 GiB-size class in the SSD offload path and was accepted as a code-only change.
clang-formatclean on the file.Checklist
./scripts/code_format.sh(clang-format)AI Assistance Disclosure
Used Claude Code to help sweep the store/transfer-engine code for the remaining 32-bit size/offset arithmetic siblings of #2570 and to draft the change. I reviewed and verified the fix (including the standalone overflow reproduction above) and am responsible for it.