From def175eb20f3249b89bfc3cf1c83a498228beb60 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Sat, 9 Sep 2023 23:04:14 +0100 Subject: [PATCH] workaround BaseException issue on Python versions before 3.11 --- src/pycell.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/pycell.rs b/src/pycell.rs index c9ba445633e..5810ebbbed9 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -204,7 +204,6 @@ use crate::type_object::{PyLayout, PySizedLayout}; use crate::types::PyAny; use crate::{ conversion::{AsPyPointer, FromPyPointer, ToPyObject}, - ffi::PyBaseObject_Type, type_object::get_tp_free, PyTypeInfo, }; @@ -967,15 +966,23 @@ where { fn ensure_threadsafe(&self) {} unsafe fn tp_dealloc(py: Python<'_>, slf: *mut ffi::PyObject) { + let type_obj = T::type_object_raw(py); // For `#[pyclass]` types which inherit from PyAny, we can just call tp_free - if T::type_object_raw(py) == &mut PyBaseObject_Type { + if type_obj == std::ptr::addr_of_mut!(ffi::PyBaseObject_Type) { return get_tp_free(ffi::Py_TYPE(slf))(slf as _); } // More complex native types (e.g. `extends=PyDict`) require calling the base's dealloc. #[cfg(not(Py_LIMITED_API))] { - if let Some(dealloc) = (*T::type_object_raw(py)).tp_dealloc { + if let Some(dealloc) = (*type_obj).tp_dealloc { + // Before Python 3.11 BaseException_dealloc would use Py_GC_UNTRACK which + // assumes the exception is currently GC tracked, so we have to re-track + // before calling the dealloc so that it can safely call Py_GC_UNTRACK. + #[cfg(not(Py_3_11))] + if ffi::PyType_FastSubclass(type_obj, ffi::Py_TPFLAGS_BASE_EXC_SUBCLASS) == 1 { + ffi::PyObject_GC_Track(slf.cast()); + } dealloc(slf as _); } else { get_tp_free(ffi::Py_TYPE(slf))(slf as _);