Skip to content

Fix OOM state-desync in generated array-member setters - #2414

Closed
rparolin wants to merge 1 commit into
NVIDIA:mainfrom
rparolin:fix/array-setter-oom-strong-guarantee
Closed

Fix OOM state-desync in generated array-member setters#2414
rparolin wants to merge 1 commit into
NVIDIA:mainfrom
rparolin:fix/array-setter-oom-strong-guarantee

Conversation

@rparolin

@rparolinrparolin commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Prepared with the assistance of an automated agent (Claude Code / Claude Opus 4.8). Please review carefully.

Summary

The generated setters for list-valued struct members (CUlaunchConfig.attrs, CUDA_MEM_ALLOC_NODE_PARAMS.accessDescs, and ~27 siblings) freed the old heap buffer before allocating the new one. On an allocation failure they raised MemoryErrorbefore updating the cached length and the C-struct pointer, leaving the wrapper with a freed buffer but a stale length and a dangling_pvt_ptr[0].<m>:

  • a later same-length assignment took the no-resize path and memcpy'd through the freed/NULL buffer -> near-NULL segfault, and
  • getPtr()-then-CUDA read the dangling pointer -> use-after-free.

Fix

Allocate and fill the new buffer first, and free/swap the old one only once the resize is known to succeed -- a strong exception guarantee. A failed (over)allocation now leaves the object completely unchanged.

Regeneration

The change is in the cybind generator template (legacy_cython_gen); this PR is the full regenerated output of:

python -m cybind --generate-module "cuda.*" --output-dir <checkout>/cuda_bindings --ctk-target-version 13.3

Besides the setter fix (18 driver + 11 runtime setters), the regen also picks up docstring-only cleanups that have landed in cybind since the last sync (e.g. nvml.pyx, runtime.pxd, cyruntime.pxd, runtime.rst). These are formatting-only -- no API, signature, or behavior changes -- and are included because they are part of what the canonical regeneration command produces.

Verification

  • Pre-fix build: reproducer SIGSEGVs on the same-length re-set after a failed resize.
  • Post-fix (regenerated) build: survives; object state intact.
  • New subprocess regression test test_array_setter_preserves_state_on_failed_resize forces the failed resize via an overflowing __len__ (so calloc overflows size_t -> NULL, no real host OOM needed). Passes; the two existing Fix a double-free bug #2112 array-setter regression tests still pass.

Context

Addresses NVBUG 6268871. Companion cybind template change is under review separately; this PR exists so the regenerated bindings get full CI.

@rparolinrparolin added bug Something isn't working P2 Low priority - Nice to have cuda.bindings Everything related to the cuda.bindings module labels Jul 23, 2026
@github-actions

Copy link
Copy Markdown

@rparolin
rparolinforce-pushed the fix/array-setter-oom-strong-guarantee branch from 2ff5f72 to 1136fdaCompareJuly 23, 2026 22:10
@rparolinrparolin changed the title Fix OOM state-desync in generated array-member setters (Glasswing V1.1)Fix OOM state-desync in generated array-member settersJul 23, 2026
@rparolin
rparolin requested a review from mdboomJuly 23, 2026 22:15
The generated setters for list-valued struct members (CUlaunchConfig.attrs,
CUDA_MEM_ALLOC_NODE_PARAMS.accessDescs, ...) freed the old buffer, then
allocated the new one; on allocation failure they raised *before* updating
the cached length and the C-struct pointer. That left the wrapper with a
freed buffer but a stale length and a dangling _pvt_ptr[0].<m>:
- a later same-length assignment took the no-resize path and memcpy'd
through the freed/NULL buffer -> near-NULL segfault, and
- getPtr()-then-CUDA read the dangling pointer -> use-after-free.
The setters now allocate and fill a new buffer first, and free/swap the old
one only once the resize is known to succeed, so a failed (over)allocation
leaves the object completely unchanged (strong exception guarantee).
The fix is made in the cybind generator template (legacy_cython_gen). These
files are the full regenerated output of
python -m cybind --generate-module "cuda.*" \
--output-dir <checkout>/cuda_bindings --ctk-target-version 13.3
so besides the setter change (18 driver + 11 runtime setters) the regen also
picks up accumulated docstring-only cleanups that have landed in cybind since
the last sync (no API/behavior change). Adds a subprocess regression test that
forces the failed resize via an overflowing __len__.
Addresses Glasswing finding V1.1 (NVBUG 6268871).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rparolin
rparolinforce-pushed the fix/array-setter-oom-strong-guarantee branch from 1136fda to 497d561CompareJuly 23, 2026 22:17
@rparolinrparolin self-assigned this Jul 23, 2026
CUDA_EMULATION_STRATEGY_EAGER
ctypedef cudaEmulationStrategy_t cudaEmulationStrategy

cdef extern from 'library_types.h':

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.

Looks like maybe there is a non-deterministic ordering bug in the generator here. Not to fix now, but I will file a bug over there.

self._pvt_ptr[0].paramsArray = _paramsArray_new
else:
for idx in range(len(val)):
string.memcpy(&self._paramsArray[idx], (<cudaExternalSemaphoreWaitParams>val[idx])._pvt_ptr, sizeof(cyruntime.cudaExternalSemaphoreWaitParams))

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.

We really should refactor this out into a function to remove all this duplication, but the legacy generator makes that hard and probably not worth the effort for something that's being deprecated.

@rparolin

rparolin commented Jul 30, 2026

Copy link
Copy Markdown
CollaboratorAuthor

Closing as superseded by #2423.

The setter fix in this PR already landed on main via #2423 ("Prepare for CTK 13.4"), which regenerated the bindings with the same allocate-fill-swap ordering. Verified identical coverage on main: 14 of 18 resize branches in driver.pyx and 7 of 11 in runtime.pyx now carry the strong-exception-guarantee pattern -- the same counts this PR produced.

This branch is a CTK 13.3 regen, so rebasing it onto 13.4 main would revert the 13.4 prep. Nothing here is worth carrying forward.

github-actionsBot pushed a commit that referenced this pull request Jul 31, 2026
Removed preview folders for the following PRs:
- PR #2414
- PR #2459
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingcuda.bindingsEverything related to the cuda.bindings moduleP2Low priority - Nice to have

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rparolin@mdboom