@@ -245,6 +245,49 @@ PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if
245245 return handle (type_info ? ((PyObject *) type_info->type ) : nullptr );
246246}
247247
248+ inline bool try_incref (PyObject *obj) {
249+ // Tries to increment the reference count of an object if it's not zero.
250+ // TODO: Use PyUnstable_TryIncref when available.
251+ // See https://github.com/python/cpython/issues/128844
252+ #ifdef Py_GIL_DISABLED
253+ // See
254+ // https://github.com/python/cpython/blob/d05140f9f77d7dfc753dd1e5ac3a5962aaa03eff/Include/internal/pycore_object.h#L761
255+ uint32_t local = _Py_atomic_load_uint32_relaxed (&obj->ob_ref_local );
256+ local += 1 ;
257+ if (local == 0 ) {
258+ // immortal
259+ return true ;
260+ }
261+ if (_Py_IsOwnedByCurrentThread (obj)) {
262+ _Py_atomic_store_uint32_relaxed (&obj->ob_ref_local , local);
263+ # ifdef Py_REF_DEBUG
264+ _Py_INCREF_IncRefTotal ();
265+ # endif
266+ return true ;
267+ }
268+ Py_ssize_t shared = _Py_atomic_load_ssize_relaxed (&obj->ob_ref_shared );
269+ for (;;) {
270+ // If the shared refcount is zero and the object is either merged
271+ // or may not have weak references, then we cannot incref it.
272+ if (shared == 0 || shared == _Py_REF_MERGED) {
273+ return false ;
274+ }
275+
276+ if (_Py_atomic_compare_exchange_ssize (
277+ &obj->ob_ref_shared , &shared, shared + (1 << _Py_REF_SHARED_SHIFT))) {
278+ # ifdef Py_REF_DEBUG
279+ _Py_INCREF_IncRefTotal ();
280+ # endif
281+ return true ;
282+ }
283+ }
284+ #else
285+ assert (Py_REFCNT (obj) > 0 );
286+ Py_INCREF (obj);
287+ return true ;
288+ #endif
289+ }
290+
248291// Searches the inheritance graph for a registered Python instance, using all_type_info().
249292PYBIND11_NOINLINE handle find_registered_python_instance (void *src,
250293 const detail::type_info *tinfo) {
@@ -253,7 +296,10 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
253296 for (auto it_i = it_instances.first ; it_i != it_instances.second ; ++it_i) {
254297 for (auto *instance_type : detail::all_type_info (Py_TYPE (it_i->second ))) {
255298 if (instance_type && same_type (*instance_type->cpptype , *tinfo->cpptype )) {
256- return handle ((PyObject *) it_i->second ).inc_ref ();
299+ auto *wrapper = reinterpret_cast <PyObject *>(it_i->second );
300+ if (try_incref (wrapper)) {
301+ return handle (wrapper);
302+ }
257303 }
258304 }
259305 }
0 commit comments