Skip to content

fix: close issue #1863 Fix Cython CUDA stream pointer conversion#2254

Open
yihong0618 wants to merge 2 commits into
NVIDIA:mainfrom
yihong0618:hy/close_issue_1863
Open

fix: close issue #1863 Fix Cython CUDA stream pointer conversion#2254
yihong0618 wants to merge 2 commits into
NVIDIA:mainfrom
yihong0618:hy/close_issue_1863

Conversation

@yihong0618

Copy link
Copy Markdown
Contributor

Convert Python stream pointer integers through uintptr_t before casting to cudaStream_t. This prevents Cython from treating the int object address as the CUDA stream handle when using Resources(stream=stream.ptr) or MultiGpuResources(stream=stream.ptr).

the reason as cython doc:

Cython type/cast syntax:
https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#statements-and-expressions
Cython pointer type documentation:
https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#types

The CPython documentation also states that extracting a C integer value from a Python int requires APIs such as PyLong_AsSize_t / PyLong_AsUnsignedLongLong:

PyLong_AsSize_t:
https://docs.python.org/3/c-api/long.html#c.PyLong_AsSize_t

At the same time, CPython also provides a dedicated PyLong_AsVoidPtr, which shows that converting a “Python integer to a C pointer value” is an explicit conversion step, and is not the same as directly casting a PyObject * to a pointer.

PyLong_AsVoidPtr:
https://docs.python.org/3/c-api/long.html#c.PyLong_AsVoidPtr


for the code side

  from cuda.bindings.cyruntime cimport cudaStream_t
  from libc.stdint cimport uintptr_t

  def old(stream):
      return <uintptr_t><cudaStream_t>stream

  def new(stream):
      return <uintptr_t><cudaStream_t><uintptr_t>stream

the generated code

# old
__Pyx_PyLong_FromSize_t(((uintptr_t)((cudaStream_t)__pyx_v_stream)))
# new
  __pyx_t_1 = __Pyx_PyLong_As_size_t(__pyx_v_stream);
  __Pyx_PyLong_FromSize_t(
      ((uintptr_t)((cudaStream_t)((uintptr_t)__pyx_t_1)))
  )

the new code make sure we get the value instead of the adress pyobject value

Convert Python stream pointer integers through uintptr_t before casting
to cudaStream_t. This prevents Cython from treating the int object
address as the CUDA stream handle when using Resources(stream=stream.ptr)
or MultiGpuResources(stream=stream.ptr).

Signed-off-by: yihong0618 <zouzou0208@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a82619f3-f340-4be9-86e0-f244b577f2f0

📥 Commits

Reviewing files that changed from the base of the PR and between 460c312 and 6381ff1.

📒 Files selected for processing (1)
  • python/cuvs/cuvs/tests/test_resources.py
💤 Files with no reviewable changes (1)
  • python/cuvs/cuvs/tests/test_resources.py

📝 Walkthrough

Summary by CodeRabbit

  • Tests

    • Added coverage to verify stream synchronization works safely when using external GPU streams (e.g., CuPy).
  • Bug Fixes

    • Improved CUDA stream pointer handling in resource synchronization by using explicit “stream provided” checks and safer pointer-sized casting, reducing the risk of crashes when syncing streams from external sources.

Walkthrough

Two Cython files (resources.pyx, mg_resources.pyx) are updated to import cudaStream_t from cuvs.common.c_api instead of cuda.bindings.cyruntime, add uintptr_t for intermediate pointer casting, replace stream truthiness checks with explicit is not None guards, and cast stream handles via <cudaStream_t><uintptr_t>. A new test file verifies that constructing Resources from a raw CuPy stream pointer and calling sync() does not segfault.

Changes

Stream Pointer Casting Fix

Layer / File(s) Summary
Import and cast correction
python/cuvs/cuvs/common/resources.pyx, python/cuvs/cuvs/common/mg_resources.pyx
cudaStream_t is now imported from cuvs.common.c_api; uintptr_t is added from libc.stdint. Stream-setup guards change from if stream: to if stream is not None, and casts to cudaStream_t go through an intermediate uintptr_t in both Resources.__cinit__ and MultiGpuResources.__cinit__.
Regression test
python/cuvs/cuvs/tests/test_resources.py
Adds test_resources_syncs_cupy_stream_pointer, which builds Resources from a CuPy stream's raw pointer (stream.ptr) and calls resources.sync() to confirm no segfault.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing issue #1863 related to CUDA stream pointer conversion in Cython code, which directly corresponds to the changeset modifications.
Description check ✅ Passed The description provides detailed technical justification for the fix, explaining the problem with Python stream pointer handling and the solution involving uintptr_t casting, directly corresponding to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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 `@python/cuvs/cuvs/tests/test_resources.py`:
- Around line 12-17: Add a sibling regression test for the MultiGpuResources
constructor path with a raw CuPy stream pointer. Create a new test function
following the same pattern as test_resources_syncs_cupy_stream_pointer that
instantiates MultiGpuResources with a CuPy stream pointer (stream.ptr) and calls
sync() on it. This ensures coverage for the MultiGpuResources constructor's
pointer-cast path which was also modified in this PR, preventing similar
pointer-cast bugs from regressing undetected.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 04361215-a002-4a8b-9c0d-c90a3da66fcd

📥 Commits

Reviewing files that changed from the base of the PR and between 71306ec and 460c312.

📒 Files selected for processing (3)
  • python/cuvs/cuvs/common/mg_resources.pyx
  • python/cuvs/cuvs/common/resources.pyx
  • python/cuvs/cuvs/tests/test_resources.py

Comment on lines +12 to +17
def test_resources_syncs_cupy_stream_pointer():
# gh-issue: 1836 should not segfault when syncing a stream pointer from cupy
stream = cp.cuda.Stream()
resources = Resources(stream=stream.ptr)

resources.sync()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

HIGH: Missing regression test for MultiGpuResources(stream=stream.ptr) cast path.

Have you considered adding a sibling regression test for MultiGpuResources with a raw CuPy stream pointer? This PR modifies that constructor path too, so without coverage a similar pointer-cast bug could regress into a crash unnoticed.

Proposed test addition
 import cupy as cp
 import cuvs.common.resources as resources_mod
 
-from cuvs.common import Resources
+from cuvs.common import MultiGpuResources, Resources
 
 
 def test_resources_syncs_cupy_stream_pointer():
     # gh-issue: 1836 should not segfault when syncing a stream pointer from cupy
     stream = cp.cuda.Stream()
     resources = Resources(stream=stream.ptr)
 
     resources.sync()
+
+
+def test_multi_gpu_resources_syncs_cupy_stream_pointer():
+    stream = cp.cuda.Stream()
+    resources = MultiGpuResources(stream=stream.ptr, device_ids=[0])
+    resources.sync()

As per coding guidelines, HIGH issues include substantial missing edge-case coverage in tests for changed paths.

🤖 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 `@python/cuvs/cuvs/tests/test_resources.py` around lines 12 - 17, Add a sibling
regression test for the MultiGpuResources constructor path with a raw CuPy
stream pointer. Create a new test function following the same pattern as
test_resources_syncs_cupy_stream_pointer that instantiates MultiGpuResources
with a CuPy stream pointer (stream.ptr) and calls sync() on it. This ensures
coverage for the MultiGpuResources constructor's pointer-cast path which was
also modified in this PR, preventing similar pointer-cast bugs from regressing
undetected.

Source: Coding guidelines

Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant