You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fix cuda.bindings: lock lazy init of _cyb_func_ptrs in driver _inspect_function_pointer - #3406
_inspect_function_pointer lazily builds a module-level _cyb_func_ptrs dict with an unsynchronized "check None, then assign". Under free-threaded Python several threads can each build and publish their own dict, and the replaced dict can be freed while another thread reads it. This is the SystemError: ... dictobject.c: bad argument to internal function seen in test_private_function_pointer_inspector on Python 3.14t.
The fix uses double-checked locking with a dedicated _cyb_func_ptrs_lock: only the first initialization takes the lock, and later lookups are lock-free reads of the published dict.
Notes
The _internal/driver_{linux,windows}.pyx files are regenerated from the cybind change (generator-side fix), not hand-edited.
lijinf2
changed the title
Lock lazy init of _cyb_func_ptrs in driver _inspect_function_pointer
Fix cuda.bindings bug: lock lazy init of _cyb_func_ptrs in driver _inspect_function_pointer
Nov 7, 2026
No actionable comments were generated in the recent review.
Summary
Summary by CodeRabbit
Bug Fixes
Improved the reliability of CUDA driver bindings on Linux and Windows when multiple threads access function pointers at the same time. Function pointers are now initialized once and consistently retrieved from the shared cache, reducing the chance of inconsistent behavior in multithreaded applications.
The Linux and Windows drivers now use a lock to initialize the cached function-pointer dictionary once. Both generated-file headers add a prerelease API warning and update the content hash.
Both drivers separate dictionary construction from cache access. They use a lock and a second cache check before storing the dictionary. The generated-file headers add a prerelease API warning and update the content hash.
Assessment against linked issues
Objective
Addressed
Explanation
Prevent test_private_function_pointer_inspector from failing under free-threaded Python on Windows [#3373]
✅
Suggested reviewers:mdboom
Change: Bug fix · Severity of issue fixed: Low
Merge Risk: Minimal · up to 45c27
The reported concurrent cache-initialization risk is addressed in both drivers. No actionable merge-blocking issue remains after normal checks.
Architecture risk: Low · up to 45c27
The change affects 1 system.
Changed systems:cuda_bindings_13
Architecture concerns
No architecture-level concerns identified.
Review details
Systems and components
observed — cuda_bindings_13 (service) was modified; 2 changed files map to changed impact.
Before / after behavior
observed — Modified behavior in cuda_bindings_13/cuda/bindings/_internal/driver_linux.pyx: Added a prerelease-API warning and updated the generated-file content hash.
observed — Modified behavior in cuda_bindings_13/cuda/bindings/_internal/driver_linux.pyx: Added _cyb_func_ptrs_lock to synchronize initialization of the cached function-pointer dictionary.
observed — Modified behavior in cuda_bindings_13/cuda/bindings/_internal/driver_linux.pyx: _build_function_pointers returns the constructed pointer dictionary without assigning it to the cache. _inspect_function_pointers now initializes that cache once using a lock and a second None check; _inspect_function_pointer delegates lookup to the cached accessor instead of initializing the cache itself.
observed — Modified behavior in cuda_bindings_13/cuda/bindings/_internal/driver_windows.pyx: Adds the prerelease-API warning and updates the generated-file content hash.
- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Tip
🎯 Customize your risk assessments
Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.
✅ Automatic approvals, with your rules
Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.
lijinf2
changed the title
Fix cuda.bindings bug: lock lazy init of _cyb_func_ptrs in driver _inspect_function_pointer
Fix cuda.bindings: lock lazy init of _cyb_func_ptrs in driver _inspect_function_pointer
Nov 7, 2026
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.
python3 - <<'PY'import importlib.metadata as metadataimport importlib.utiltry: print("Cython version:", metadata.version("Cython")) spec = importlib.util.find_spec("Cython") print("Cython source root:", list(spec.submodule_search_locations) if spec else None)except metadata.PackageNotFoundError: print("Cython distribution unavailable")PY
Repository: NVIDIA/cuda-python
Length of output: 188
important: Synchronize both cache writers.
On free-threaded Python, a direct call to _inspect_function_pointers() can overlap the first _inspect_function_pointer() call and replace _cyb_func_ptrs without the lock. This can cause unsafe reference access or a crash.
Coordinate initialization in both entry points. Avoid acquiring the non-reentrant lock twice. Update the generator and regenerate both platform variants.
For Cython 3 free-threaded Python, are cdef module-level Python object variables automatically protected for concurrent reads and writes? Does a lock held by writers alone make an unlocked reader safe? Find relevant Cython and CPython documentation.
In Cython 3.2.5 free-threaded Python, are reads and assignments to cdef module-level Python object variables automatically atomic or synchronized? Find documentation or Cython source evidence for concurrent read/write safety and memory publication.
Length of output: 30296
Script executed:
#!/bin/bashset -euo pipefail
tmp=$(mktemp -d)trap'rm -rf "$tmp"' EXIT
python3 -m pip install --disable-pip-version-check --quiet --target "$tmp/packages"'Cython==3.2.5'
cat >"$tmp/cache_example.pyx"<<'EOF'# cython: freethreading_compatible=Trueimport threadingcdef dict cache = Nonecdef object lock = threading.Lock()cdef dict build(): return {"key": 1}cpdef dict inspect_cache(): global cache if cache is None: with lock: if cache is None: cache = build() return cacheEOF
PYTHONPATH="$tmp/packages" python3 -m cython -3 -o "$tmp/cache_example.c""$tmp/cache_example.pyx"echo'--- generated cache reads and writes ---'
rg -n -C 3 '__pyx_v_13cache_example_cache|__pyx_f_13cache_example_inspect_cache'"$tmp/cache_example.c"| head -170
Length of output: 3882
@lijinf2 important: Both entry points now share one initializer, but the first read of _cyb_func_ptrs remains outside the lock. It can race with the assignment during initialization on free-threaded Python.
A standalone Cython 3.2.5 translation of this pattern emitted ordinary C pointer accesses. Please protect the read and assignment with the same lock, or use a safe acquire/release publication scheme.
Both platform variants have the same implementation. I could not inspect the generator source or run the repository tests. Please verify the generator change and run a concurrent first-call test for both entry points on Windows Python 3.14t.
Learnings used
Learnt from: CR
Repo: NVIDIA/cuda-python PR: 0
File: cuda_bindings_13/AGENTS.md:0-0
Timestamp: 2026-10-20T22:59:48.070Z
Learning: Applies to cuda_bindings_13/cuda/bindings/_internal/driver_linux.pyx : Source excerpt:
## Generated-source workflow
- **Platform split files**: keep `_linux.pyx` and `_windows.pyx` variants
aligned when behavior should be equivalent.
Learnt from: CR
Repo: NVIDIA/cuda-python PR: 0
File: cuda_bindings_13/CLAUDE.md:0-0
Timestamp: 2026-10-31T04:59:49.354Z
Learning: Applies to cuda_bindings_13/cuda/bindings/_internal/driver_linux.pyx : Source excerpt:
## Generated-source workflow
- **Platform split files**: keep `_linux.pyx` and `_windows.pyx` variants
aligned when behavior should be equivalent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bugSomething isn't workingcuda.bindingsEverything related to the cuda.bindings module
1 participant
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3373
reference cybind MR#: 619
Summary
_inspect_function_pointerlazily builds a module-level_cyb_func_ptrsdict with an unsynchronized "check None, then assign". Under free-threaded Python several threads can each build and publish their own dict, and the replaced dict can be freed while another thread reads it. This is theSystemError: ... dictobject.c: bad argument to internal functionseen intest_private_function_pointer_inspectoron Python 3.14t.The fix uses double-checked locking with a dedicated
_cyb_func_ptrs_lock: only the first initialization takes the lock, and later lookups are lock-free reads of the published dict.Notes
_internal/driver_{linux,windows}.pyxfiles are regenerated from the cybind change (generator-side fix), not hand-edited.🤖 Generated with Claude Code