Skip to content

fix: prevent unsigned integer underflow in NVML memory info hook#201

Open
miaobyte wants to merge 2 commits into
Project-HAMi:mainfrom
array2d:fix/nvml-memory-underflow
Open

fix: prevent unsigned integer underflow in NVML memory info hook#201
miaobyte wants to merge 2 commits into
Project-HAMi:mainfrom
array2d:fix/nvml-memory-underflow

Conversation

@miaobyte

@miaobyte miaobyte commented Jun 4, 2026

Copy link
Copy Markdown

Summary

Fix unsigned integer underflow in _nvmlDeviceGetMemoryInfo: when GPU memory usage exceeds the configured limit, (limit - usage) with unsigned size_t wraps to ~18 EB, breaking monitoring tools.

Changes

src/nvml/hook.c: compute clamped = (usage > limit) ? limit : usage, then derive both used = clamped and free = limit - clamped. This guarantees free + used = total always holds and free never underflows.

Fixes #200

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Corrected reported GPU and CUDA memory values when actual usage exceeds the configured memory limit.
    • Prevented invalid or underflowed free-memory results.
    • Added warnings when memory usage exceeds the configured limit.

@hami-robot
hami-robot Bot requested a review from archlitchi June 4, 2026 08:16
@hami-robot

hami-robot Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: miaobyte
Once this PR has been reviewed and has the lgtm label, please assign archlitchi for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@hami-robot
hami-robot Bot requested a review from chaunceyjiang June 4, 2026 08:16
@hami-robot hami-robot Bot added the size/XS label Jun 4, 2026
@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from 34a7e14 to 4c26dce Compare June 4, 2026 08:44
@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from 4c26dce to 58d0f3c Compare June 4, 2026 08:48
@hami-robot hami-robot Bot added size/L and removed size/XS labels Jun 4, 2026
When usage > limit, (limit - usage) wraps around to a massive unsigned
value (~18 EB). Clamp both free and used so that free + used = total
always holds, preventing corrupted values in monitoring tools.

Fixes Project-HAMi#200
Signed-off-by: peng.li24 <peng.li24@nio.com>

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from 58d0f3c to 668ecb8 Compare June 4, 2026 08:49
@hami-robot hami-robot Bot added size/XS and removed size/L labels Jun 4, 2026
@miaobyte miaobyte changed the title fix: prevent unsigned integer underflow when usage exceeds memory limit fix: prevent unsigned integer underflow in NVML memory info hook Jun 4, 2026
Comment thread src/nvml/hook.c
switch (version) {
case 1:
((nvmlMemory_t*)memory)->free = (limit-usage);
((nvmlMemory_t*)memory)->free = limit - clamped;

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.

This silently clamps the value without logging, so operators can't tell usage actually exceeded the limit.

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.

Agreed, a LOG_WARN here would help operators detect when usage exceeded the limit. Something like:

size_t clamped = (usage > limit) ? limit : usage;
if (usage > limit) {
    LOG_WARN("NVML meminfo: usage %lu exceeds limit %lu, clamping", usage, limit);
}

@mesutoezdil

Copy link
Copy Markdown
Contributor

This only fixes the NVML hook, not the CUDA hook underflow from the same issue, so closing #200 here would be premature.

@maverick123123

Copy link
Copy Markdown
Contributor

已收到,正在 review 你的 PR。

@maverick123123

Copy link
Copy Markdown
Contributor

Thanks for the review @mesutoezdil. Agreed on both points:

  1. Need LOG_WARN — silently clamping hides the fact that usage drifted above limit, which operators need visibility into
  2. CUDA hook also needs fixing — the return CUDA_ERROR_INVALID_VALUE path in src/cuda/memory.c should be similarly clamped rather than returning an error, otherwise applications calling cuMemGetInfo may crash or behave unpredictably

@miaobyte please update when you have a chance.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@miaobyte, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 63c3def8-9c1a-44bd-a94f-5bfd11ab34e2

📥 Commits

Reviewing files that changed from the base of the PR and between b72a46f and c56e601.

📒 Files selected for processing (2)
  • src/cuda/memory.c
  • src/nvml/hook.c
📝 Walkthrough

Walkthrough

CUDA and NVML memory hooks now handle usage exceeding configured limits by logging warnings, clamping usage, and reporting bounded memory values instead of errors or underflowed free memory.

Changes

Memory Usage Clamping

Layer / File(s) Summary
Clamp CUDA and NVML memory reports
src/cuda/memory.c, src/nvml/hook.c
CUDA clamps over-limit usage while preserving the underlying query and limit calculations. NVML clamps usage and recalculates free, total, and used for both memory API versions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: chaunceyjiang, archlitchi, mesutoezdil

Poem

I’m a rabbit with numbers neat,
No giant free-memory leaps.
CUDA clamps with warning bright,
NVML keeps its values right.
Bounded bytes now softly sleep.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main bug fix, though it mentions only the NVML side of the change.
Linked Issues check ✅ Passed The PR implements the requested NVML clamping and updates the CUDA hook to clamp instead of erroring, matching issue #200.
Out of Scope Changes check ✅ Passed The changes stay within the memory-hook underflow fix in the two referenced source files and add no unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from b5007c1 to b72a46f Compare July 24, 2026 03:50
@coderabbitai
coderabbitai Bot requested a review from mesutoezdil July 24, 2026 03:52
@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from b72a46f to 3c3d82f Compare July 24, 2026 03:53
cuMemGetInfo_v2: usage 超过 limit 时不再返回 INVALID_VALUE,
而是 clamp 到 limit 再计算 free memory。
nvmlDeviceGetMemoryInfo: 同样添加 clamp + 警告日志。

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: peng.li24 <734991033@qq.com>
Signed-off-by: miaobyte <lipeng@mirrorsoft.cn>
@miaobyte
miaobyte force-pushed the fix/nvml-memory-underflow branch from 3c3d82f to c56e601 Compare July 24, 2026 03:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/nvml/hook.c`:
- Around line 356-369: Update the NVML memory handling around the version switch
to derive actual_limit as the minimum of the configured limit and the original
NVML-reported total. Use actual_limit for usage clamping and for the free and
total fields in both nvmlMemory_t and nvmlMemory_v2_t, and warn when usage
exceeds actual_limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 44929024-f7e6-470f-8905-80b61a875ce9

📥 Commits

Reviewing files that changed from the base of the PR and between 52f33fc and b72a46f.

📒 Files selected for processing (2)
  • src/cuda/memory.c
  • src/nvml/hook.c

Comment thread src/nvml/hook.c
Comment on lines +356 to +369
if (usage > limit) {
LOG_WARN("usage(%ld) exceeds limit(%ld), clamping", usage, limit);
}
size_t clamped = (usage > limit) ? limit : usage;
switch (version) {
case 1:
((nvmlMemory_t*)memory)->free = (limit-usage);
((nvmlMemory_t*)memory)->free = limit - clamped;
((nvmlMemory_t*)memory)->total = limit;
((nvmlMemory_t*)memory)->used = usage;
((nvmlMemory_t*)memory)->used = clamped;
return NVML_SUCCESS;
case 2:
((nvmlMemory_v2_t *)memory)->free = (limit-usage);
((nvmlMemory_v2_t *)memory)->free = limit - clamped;
((nvmlMemory_v2_t *)memory)->total = limit;
((nvmlMemory_v2_t *)memory)->used = usage;
((nvmlMemory_v2_t *)memory)->used = clamped;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Cap NVML’s effective limit by the physical total.

Unlike src/cuda/memory.c Lines 522-526, this path sets total = limit unconditionally. If the configured limit exceeds the underlying NVML-reported total, NVML can return physically impossible total and free values. Compute actual_limit = min(limit, original_total), clamp usage to that value, and warn when usage > actual_limit so both hooks report the same bounded memory contract.

Proposed fix
+    size_t original_total = version == 1
+        ? ((nvmlMemory_t*)memory)->total
+        : ((nvmlMemory_v2_t*)memory)->total;
+    size_t actual_limit = (limit < original_total) ? limit : original_total;
-    if (usage > limit) {
-        LOG_WARN("usage(%ld) exceeds limit(%ld), clamping", usage, limit);
+    if (usage > actual_limit) {
+        LOG_WARN("usage(%zu) exceeds effective limit(%zu), clamping",
+            usage, actual_limit);
     }
-    size_t clamped = (usage > limit) ? limit : usage;
+    size_t clamped = (usage > actual_limit) ? actual_limit : usage;
...
-        ((nvmlMemory_t*)memory)->free = limit - clamped;
-        ((nvmlMemory_t*)memory)->total = limit;
+        ((nvmlMemory_t*)memory)->free = actual_limit - clamped;
+        ((nvmlMemory_t*)memory)->total = actual_limit;
...
-        ((nvmlMemory_v2_t *)memory)->free = limit - clamped;
-        ((nvmlMemory_v2_t *)memory)->total = limit;
+        ((nvmlMemory_v2_t *)memory)->free = actual_limit - clamped;
+        ((nvmlMemory_v2_t *)memory)->total = actual_limit;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (usage > limit) {
LOG_WARN("usage(%ld) exceeds limit(%ld), clamping", usage, limit);
}
size_t clamped = (usage > limit) ? limit : usage;
switch (version) {
case 1:
((nvmlMemory_t*)memory)->free = (limit-usage);
((nvmlMemory_t*)memory)->free = limit - clamped;
((nvmlMemory_t*)memory)->total = limit;
((nvmlMemory_t*)memory)->used = usage;
((nvmlMemory_t*)memory)->used = clamped;
return NVML_SUCCESS;
case 2:
((nvmlMemory_v2_t *)memory)->free = (limit-usage);
((nvmlMemory_v2_t *)memory)->free = limit - clamped;
((nvmlMemory_v2_t *)memory)->total = limit;
((nvmlMemory_v2_t *)memory)->used = usage;
((nvmlMemory_v2_t *)memory)->used = clamped;
size_t original_total = version == 1
? ((nvmlMemory_t*)memory)->total
: ((nvmlMemory_v2_t*)memory)->total;
size_t actual_limit = (limit < original_total) ? limit : original_total;
if (usage > actual_limit) {
LOG_WARN("usage(%zu) exceeds effective limit(%zu), clamping",
usage, actual_limit);
}
size_t clamped = (usage > actual_limit) ? actual_limit : usage;
switch (version) {
case 1:
((nvmlMemory_t*)memory)->free = actual_limit - clamped;
((nvmlMemory_t*)memory)->total = actual_limit;
((nvmlMemory_t*)memory)->used = clamped;
return NVML_SUCCESS;
case 2:
((nvmlMemory_v2_t *)memory)->free = actual_limit - clamped;
((nvmlMemory_v2_t *)memory)->total = actual_limit;
((nvmlMemory_v2_t *)memory)->used = clamped;
🧰 Tools
🪛 Cppcheck (2.21.0)

[warning] 357-357: If resource allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfResources)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/nvml/hook.c` around lines 356 - 369, Update the NVML memory handling
around the version switch to derive actual_limit as the minimum of the
configured limit and the original NVML-reported total. Use actual_limit for
usage clamping and for the free and total fields in both nvmlMemory_t and
nvmlMemory_v2_t, and warn when usage exceeds actual_limit.

@miaobyte

Copy link
Copy Markdown
Author

@maverick123123 @mesutoezdil

done,now updated:

NVML hook (src/nvml/hook.c)

  • Added LOG_WARN("NVML meminfo: usage %lu exceeds limit %lu, clamping", ...) when usage > limit, so operators have visibility into the over-limit condition.

CUDA hook (src/cuda/memory.c)

  • Removed the return CUDA_ERROR_INVALID_VALUE path when usage > limit — it now clamps usage to limit and reports free=0, total=actual_limit, matching the NVML hook behavior. This prevents cuMemGetInfo callers from crashing or seeing unpredictable values.
  • Added LOG_WARN("CUDA meminfo: usage %lu exceeds limit %lu, clamping", ...) with the same pattern for consistency.

Both hooks now handle usage > limit identically: clamp, warn, and report free=0 / total=limit.

@maverick123123

Copy link
Copy Markdown
Contributor

收到,我们先测试一下。

@maverick123123

Copy link
Copy Markdown
Contributor

测试通过,8x RTX 3090 上编译和运行均正常。@archlitchi 可以 merge 了。

@mesutoezdil

Copy link
Copy Markdown
Contributor

@miaobyte Thanks for the updates, LOG_WARN and the CUDA fix look good.

One item from CodeRabbit's review is still open though: on the NVML side, total is set to limit unconditionally, without capping it against the GPU's actual physical total like the CUDA path does (actual_limit = min(limit, *total)). If the configured limit is set higher than the real GPU memory, NVML would report an impossible total.

Can you apply the same min() clamp on the NVML side before we merge?

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.

Bug: NVML/CUDA memory hooks report corrupted values when usage exceeds limit (integer underflow)

3 participants