Skip to content

Commit 2417006

Browse files
committed
fix(core): return None from handle properties during Python shutdown
During interpreter finalization, `as_py()` calls `PyImport_ImportModule` which fails because `sys.modules` is being cleared. Guard `make_py()` with `py_is_finalizing()` to return None gracefully instead of raising. Also consolidates the `py_is_finalizing()` helper into the shared header, removing the duplicate definition from resource_handles.cpp. Closes #1748 Made-with: Cursor
1 parent 9b74eaf commit 2417006

File tree

2 files changed

+17
-13
lines changed

2 files changed

+17
-13
lines changed

cuda_core/cuda/core/_cpp/resource_handles.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,7 @@ NvJitLinkDestroyFn p_nvJitLinkDestroy = nullptr;
7777

7878
namespace {
7979

80-
#if PY_VERSION_HEX < 0x030D0000
81-
extern "C" int _Py_IsFinalizing(void);
82-
#endif
83-
84-
inline bool py_is_finalizing() noexcept {
85-
#if PY_VERSION_HEX >= 0x030D0000
86-
return Py_IsFinalizing();
87-
#else
88-
// Python < 3.13 does not expose Py_IsFinalizing() publicly. Use the private
89-
// API that exists in those versions.
90-
return _Py_IsFinalizing() != 0;
91-
#endif
92-
}
80+
using cuda_core::detail::py_is_finalizing;
9381

9482
// Helper to release the GIL while calling into the CUDA driver.
9583
// This guard is *conditional*: if the caller already dropped the GIL,

cuda_core/cuda/core/_cpp/resource_handles.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,24 @@ inline std::intptr_t as_intptr(const CuLinkHandle& h) noexcept {
517517

518518
// as_py() - convert handle to Python wrapper object (returns new reference)
519519
namespace detail {
520+
521+
#if PY_VERSION_HEX < 0x030D0000
522+
extern "C" int _Py_IsFinalizing(void);
523+
#endif
524+
525+
inline bool py_is_finalizing() noexcept {
526+
#if PY_VERSION_HEX >= 0x030D0000
527+
return Py_IsFinalizing();
528+
#else
529+
return _Py_IsFinalizing() != 0;
530+
#endif
531+
}
532+
520533
// n.b. class lookup is not cached to avoid deadlock hazard, see DESIGN.md
521534
inline PyObject* make_py(const char* module_name, const char* class_name, std::intptr_t value) noexcept {
535+
if (py_is_finalizing()) {
536+
Py_RETURN_NONE;
537+
}
522538
PyObject* mod = PyImport_ImportModule(module_name);
523539
if (!mod) return nullptr;
524540
PyObject* cls = PyObject_GetAttrString(mod, class_name);

0 commit comments

Comments
 (0)