Skip to content

Commit 1809575

Browse files
committed
fix(bindings): backport CUDA 12 utility runtime fixes
Signed-off-by: Ralf W. Grosse-Kunstleve <[email protected]>
1 parent f568268 commit 1809575

8 files changed

Lines changed: 51 additions & 4 deletions

File tree

‎cuda_bindings/cuda/bindings/_internal/utils.pyx‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,14 @@ cdef int get_nested_resource_ptr(nested_resource[ResT] &in_out_ptr, object obj,
9898
nested_ptr.reset(nested_vec, True)
9999
for i, obj_i in enumerate(obj):
100100
if ResT is char:
101-
obj_i_bytes = (<str?>(obj_i)).encode()
101+
obj_i_type = type(obj_i)
102+
if obj_i_type is str:
103+
obj_i_bytes = obj_i.encode("utf-8")
104+
elif obj_i_type is bytes:
105+
obj_i_bytes = obj_i
106+
else:
107+
raise TypeError(
108+
f"Expected str or bytes, got {obj_i_type.__name__}")
102109
str_len = <size_t>(len(obj_i_bytes)) + 1 # including null termination
103110
deref(nested_res_vec)[i].resize(str_len)
104111
obj_i_ptr = <char*>(obj_i_bytes)

‎cuda_bindings/cuda/bindings/_lib/utils.pxd‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ cdef class _HelperCUcoredumpSettings:
152152
cdef cydriver.CUcoredumpSettings_enum _attrib
153153
cdef bint _is_getter
154154
cdef size_t _size
155+
cdef object _references # keeps caller bytes alive so _charstar stays valid
155156

156157
# Return values
157158
cdef cpp_bool _bool

‎cuda_bindings/cuda/bindings/_lib/utils.pxi‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ cdef class _HelperCUcoredumpSettings:
734734
self._cptr = <void*><void_ptr>self._charstar
735735
self._size = 1024
736736
else:
737+
# Keep a reference so the borrowed _charstar buffer stays alive.
738+
self._references = init_value
737739
self._charstar = init_value
738740
self._cptr = <void*><void_ptr>self._charstar
739741
self._size = len(init_value)
@@ -756,7 +758,9 @@ cdef class _HelperCUcoredumpSettings:
756758
raise TypeError('Unsupported attribute: {}'.format(attr.name))
757759

758760
def __dealloc__(self):
759-
pass
761+
# Only the getter owns heap storage; the setter borrows caller bytes.
762+
if self._is_getter:
763+
free(self._charstar)
760764

761765
@property
762766
def cptr(self):

‎cuda_bindings/cuda/bindings/utils/__init__.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ def get_cuda_native_handle(obj: Any) -> int:
2626
"""
2727
obj_type = type(obj)
2828
try:
29-
return _handle_getters[obj_type](obj)
29+
getter = _handle_getters[obj_type]
3030
except KeyError:
3131
raise TypeError("Unknown type: " + str(obj_type)) from None
32+
# Deliberately outside the try: a KeyError raised by the getter itself is a
33+
# bug in that getter, not an unregistered type.
34+
return getter(obj)

‎cuda_bindings/docs/source/release/12.X.Y-notes.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ Highlights
3333
Bug fixes
3434
---------
3535

36+
* Nested resource pointer conversion accepts both ``str`` and ``bytes`` options.
37+
* Coredump settings retain borrowed string buffers during calls and free getter buffers.
38+
* ``get_cuda_native_handle`` preserves errors raised inside registered getters.
39+
3640

3741
Miscellaneous
3842
-------------

‎cuda_bindings/tests/test_nvjitlink.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ def test_create_and_destroy(option):
100100
nvjitlink.destroy(handle)
101101

102102

103+
@pytest.mark.human_authored
104+
def test_create_and_destroy_bytes_options():
105+
handle = nvjitlink.create(1, [b"-arch=sm_80"])
106+
assert handle != 0
107+
nvjitlink.destroy(handle)
108+
109+
103110
@pytest.mark.parametrize("option", ARCHITECTURES)
104111
def test_complete_empty(option):
105112
handle = nvjitlink.create(1, [f"-arch={option}"])

‎cuda_bindings/tests/test_nvvm.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def test_get_buffer_empty(get_size, get_buffer):
246246
assert buffer == b"\x00"
247247

248248

249-
@pytest.mark.parametrize("options", [[], ["-opt=0"], ["-opt=3", "-g"]])
249+
@pytest.mark.parametrize("options", [[], ["-opt=0"], ["-opt=3", "-g"], [b"-opt=0"]])
250250
def test_compile_program_with_minimal_nvvm_ir(minimal_nvvmir, options):
251251
with nvvm_program() as prog:
252252
nvvm.add_module_to_program(prog, minimal_nvvmir, len(minimal_nvvmir), "FileNameHere.ll")

‎cuda_bindings/tests/test_utils.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ def test_get_handle_error(target):
9292
handle = get_cuda_native_handle(target)
9393

9494

95+
@pytest.mark.agent_authored(model="claude-opus-5")
96+
def test_get_handle_does_not_report_a_registered_type_as_unknown(monkeypatch):
97+
"""A KeyError from inside a handle getter is a bug in that getter.
98+
99+
Reporting it as "Unknown type" is wrong twice over: the type *is*
100+
registered, and `from None` hides the traceback that would say otherwise.
101+
"""
102+
from cuda.bindings.utils import _handle_getters
103+
104+
class Registered:
105+
pass
106+
107+
def getter(_obj):
108+
raise KeyError("lookup inside the getter failed")
109+
110+
monkeypatch.setitem(_handle_getters, Registered, getter)
111+
112+
with pytest.raises(KeyError, match="lookup inside the getter failed"):
113+
get_cuda_native_handle(Registered())
114+
115+
95116
@pytest.mark.parametrize(
96117
"module",
97118
[

0 commit comments

Comments
 (0)