From cabb466057c53d1ff065384ff86c8a98719f3bc2 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Mon, 13 Oct 2025 20:59:57 -0700 Subject: [PATCH] Use strong reference APIs. For the free-threaded build, it is not safe use borrowed references. Another thread could deallocate the object and cause the reference to become invalid. Replace API calls that borrow references with strong reference APIs. --- src/dict.cpp | 8 ++++++++ src/object/function_doc_signature.cpp | 15 +++++++++++++-- src/wrapper.cpp | 20 ++++++++++++++------ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/dict.cpp b/src/dict.cpp index 77d840d4..296bc21e 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -68,8 +68,16 @@ object dict_base::get(object_cref k) const { if (check_exact(this)) { +#ifdef Py_GIL_DISABLED + PyObject* result; + if (PyDict_GetItemRef(this->ptr(),k.ptr(),&result) < 0) { + throw_error_already_set(); + } + return object(detail::new_reference(result ? result : Py_None)); +#else PyObject* result = PyDict_GetItem(this->ptr(),k.ptr()); return object(detail::borrowed_reference(result ? result : Py_None)); +#endif } else { diff --git a/src/object/function_doc_signature.cpp b/src/object/function_doc_signature.cpp index 18d45869..76b620dc 100644 --- a/src/object/function_doc_signature.cpp +++ b/src/object/function_doc_signature.cpp @@ -135,7 +135,15 @@ namespace boost { namespace python { namespace objects { str name(get_qualname(py_type)); if ( py_type->tp_flags & Py_TPFLAGS_HEAPTYPE ) { // Qualify the type name if it is defined in a different module. - PyObject *type_module_name = PyDict_GetItemString(py_type->tp_dict, "__module__"); + PyObject *type_module_name; +#if PY_VERSION_HEX >= 0x030D0000 + if (PyDict_GetItemStringRef(py_type->tp_dict, "__module__", &type_module_name) < 0) { + throw_error_already_set(); + } +#else + type_module_name = PyDict_GetItemString(py_type->tp_dict, "__module__"); + Py_XINCREF(type_module_name); +#endif if ( type_module_name && PyObject_RichCompareBool( @@ -144,8 +152,11 @@ namespace boost { namespace python { namespace objects { Py_NE ) != 0 ) { - return str("%s.%s" % make_tuple(handle<>(borrowed(type_module_name)), name)); + str result = str("%s.%s" % make_tuple(handle<>(type_module_name), name)); + return result; } + // Clean up the strong reference if we didn't use it + Py_XDECREF(type_module_name); } return name; } else { diff --git a/src/wrapper.cpp b/src/wrapper.cpp index 8b1b8847..2b053d83 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -21,20 +21,28 @@ namespace detail this->m_self, const_cast(name)))) ) { - PyObject* borrowed_f = 0; - + PyObject* class_f = 0; + if ( PyMethod_Check(m.get()) && PyMethod_GET_SELF(m.get()) == this->m_self && class_object->tp_dict != 0 ) { - borrowed_f = ::PyDict_GetItemString( +#if PY_VERSION_HEX >= 0x030D0000 + if (::PyDict_GetItemStringRef( + class_object->tp_dict, const_cast(name), &class_f) < 0) { + throw_error_already_set(); + } +#else + class_f = ::PyDict_GetItemString( class_object->tp_dict, const_cast(name)); - - + Py_XINCREF(class_f); +#endif } - if (borrowed_f != PyMethod_GET_FUNCTION(m.get())) + bool is_override = (class_f != PyMethod_GET_FUNCTION(m.get())); + Py_XDECREF(class_f); + if (is_override) return override(m); } }