From 35e14d09553e0e34e6fe5df4706fb3757954610b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Oct 2026 10:24:25 -0700 Subject: [PATCH 1/3] Backport bytes compiler options support to CUDA 12 Carry forward the runtime behavior from #1665/#1698 with its nvJitLink regression and NVVM bytes-options case. Extracted from #3173 so source integration can be reviewed independently. Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_12/cuda/bindings/_internal/utils.pyx | 9 ++++++++- cuda_bindings_12/tests/test_nvjitlink.py | 7 +++++++ cuda_bindings_12/tests/test_nvvm.py | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cuda_bindings_12/cuda/bindings/_internal/utils.pyx b/cuda_bindings_12/cuda/bindings/_internal/utils.pyx index df17a9e47df..ce9012113df 100644 --- a/cuda_bindings_12/cuda/bindings/_internal/utils.pyx +++ b/cuda_bindings_12/cuda/bindings/_internal/utils.pyx @@ -98,7 +98,14 @@ cdef int get_nested_resource_ptr(nested_resource[ResT] &in_out_ptr, object obj, nested_ptr.reset(nested_vec, True) for i, obj_i in enumerate(obj): if ResT is char: - obj_i_bytes = ((obj_i)).encode() + obj_i_type = type(obj_i) + if obj_i_type is str: + obj_i_bytes = obj_i.encode("utf-8") + elif obj_i_type is bytes: + obj_i_bytes = obj_i + else: + raise TypeError( + f"Expected str or bytes, got {obj_i_type.__name__}") str_len = (len(obj_i_bytes)) + 1 # including null termination deref(nested_res_vec)[i].resize(str_len) obj_i_ptr = (obj_i_bytes) diff --git a/cuda_bindings_12/tests/test_nvjitlink.py b/cuda_bindings_12/tests/test_nvjitlink.py index 19dc040e47d..bec58b7a048 100644 --- a/cuda_bindings_12/tests/test_nvjitlink.py +++ b/cuda_bindings_12/tests/test_nvjitlink.py @@ -100,6 +100,13 @@ def test_create_and_destroy(option): nvjitlink.destroy(handle) +@pytest.mark.human_authored +def test_create_and_destroy_bytes_options(): + handle = nvjitlink.create(1, [b"-arch=sm_80"]) + assert handle != 0 + nvjitlink.destroy(handle) + + @pytest.mark.parametrize("option", ARCHITECTURES) def test_complete_empty(option): handle = nvjitlink.create(1, [f"-arch={option}"]) diff --git a/cuda_bindings_12/tests/test_nvvm.py b/cuda_bindings_12/tests/test_nvvm.py index bd6f49f03f1..3cea5a0f817 100644 --- a/cuda_bindings_12/tests/test_nvvm.py +++ b/cuda_bindings_12/tests/test_nvvm.py @@ -246,7 +246,7 @@ def test_get_buffer_empty(get_size, get_buffer): assert buffer == b"\x00" -@pytest.mark.parametrize("options", [[], ["-opt=0"], ["-opt=3", "-g"]]) +@pytest.mark.parametrize("options", [[], ["-opt=0"], ["-opt=3", "-g"], [b"-opt=0"]]) def test_compile_program_with_minimal_nvvm_ir(minimal_nvvmir, options): with nvvm_program() as prog: nvvm.add_module_to_program(prog, minimal_nvvmir, len(minimal_nvvmir), "FileNameHere.ll") From b0329c256b9d22c71415065a1b3cb3eafb4b769b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Oct 2026 10:24:29 -0700 Subject: [PATCH 2/3] Backport coredump buffer ownership fixes to CUDA 12 Carry forward #2399: retain borrowed setter bytes and release getter-owned storage. Keep this runtime maintenance separate from the build integration. Signed-off-by: Ralf W. Grosse-Kunstleve --- cuda_bindings_12/cuda/bindings/_lib/utils.pxd | 1 + cuda_bindings_12/cuda/bindings/_lib/utils.pxi | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cuda_bindings_12/cuda/bindings/_lib/utils.pxd b/cuda_bindings_12/cuda/bindings/_lib/utils.pxd index 706c6d3fc7a..c36ddfb0d12 100644 --- a/cuda_bindings_12/cuda/bindings/_lib/utils.pxd +++ b/cuda_bindings_12/cuda/bindings/_lib/utils.pxd @@ -152,6 +152,7 @@ cdef class _HelperCUcoredumpSettings: cdef cydriver.CUcoredumpSettings_enum _attrib cdef bint _is_getter cdef size_t _size + cdef object _references # keeps caller bytes alive so _charstar stays valid # Return values cdef cpp_bool _bool diff --git a/cuda_bindings_12/cuda/bindings/_lib/utils.pxi b/cuda_bindings_12/cuda/bindings/_lib/utils.pxi index c11d0d0c197..eebdd17b41e 100644 --- a/cuda_bindings_12/cuda/bindings/_lib/utils.pxi +++ b/cuda_bindings_12/cuda/bindings/_lib/utils.pxi @@ -734,6 +734,8 @@ cdef class _HelperCUcoredumpSettings: self._cptr = self._charstar self._size = 1024 else: + # Keep a reference so the borrowed _charstar buffer stays alive. + self._references = init_value self._charstar = init_value self._cptr = self._charstar self._size = len(init_value) @@ -756,7 +758,9 @@ cdef class _HelperCUcoredumpSettings: raise TypeError('Unsupported attribute: {}'.format(attr.name)) def __dealloc__(self): - pass + # Only the getter owns heap storage; the setter borrows caller bytes. + if self._is_getter: + free(self._charstar) @property def cptr(self): From b01e4ad8c4707be90ac0c8275b92d211ab086126 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Oct 2026 10:24:33 -0700 Subject: [PATCH 3/3] Preserve CUDA 12 registered handle getter errors Carry forward #2551 and its regression test. A KeyError inside a registered getter must propagate instead of being reported as an unknown handle type. Signed-off-by: Ralf W. Grosse-Kunstleve --- .../cuda/bindings/utils/__init__.py | 5 ++++- cuda_bindings_12/tests/test_utils.py | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cuda_bindings_12/cuda/bindings/utils/__init__.py b/cuda_bindings_12/cuda/bindings/utils/__init__.py index 62d083dc7c6..d6136da14b0 100644 --- a/cuda_bindings_12/cuda/bindings/utils/__init__.py +++ b/cuda_bindings_12/cuda/bindings/utils/__init__.py @@ -26,6 +26,9 @@ def get_cuda_native_handle(obj: Any) -> int: """ obj_type = type(obj) try: - return _handle_getters[obj_type](obj) + getter = _handle_getters[obj_type] except KeyError: raise TypeError("Unknown type: " + str(obj_type)) from None + # Deliberately outside the try: a KeyError raised by the getter itself is a + # bug in that getter, not an unregistered type. + return getter(obj) diff --git a/cuda_bindings_12/tests/test_utils.py b/cuda_bindings_12/tests/test_utils.py index 8904d65d2ed..33487c7f529 100644 --- a/cuda_bindings_12/tests/test_utils.py +++ b/cuda_bindings_12/tests/test_utils.py @@ -92,6 +92,27 @@ def test_get_handle_error(target): handle = get_cuda_native_handle(target) +@pytest.mark.agent_authored(model="claude-opus-5") +def test_get_handle_does_not_report_a_registered_type_as_unknown(monkeypatch): + """A KeyError from inside a handle getter is a bug in that getter. + + Reporting it as "Unknown type" is wrong twice over: the type *is* + registered, and `from None` hides the traceback that would say otherwise. + """ + from cuda.bindings.utils import _handle_getters + + class Registered: + pass + + def getter(_obj): + raise KeyError("lookup inside the getter failed") + + monkeypatch.setitem(_handle_getters, Registered, getter) + + with pytest.raises(KeyError, match="lookup inside the getter failed"): + get_cuda_native_handle(Registered()) + + @pytest.mark.parametrize( "module", [