diff --git a/guide/src/class.md b/guide/src/class.md index 70c8a9abdf4..261789ade6a 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -927,7 +927,7 @@ unsafe impl pyo3::PyTypeInfo for MyClass { const FLAGS: usize = 0; #[inline] - fn type_object_raw(py: pyo3::Python) -> &'static pyo3::ffi::PyTypeObject { + fn type_object_raw(py: pyo3::Python) -> *mut pyo3::ffi::PyTypeObject { use pyo3::type_object::LazyStaticType; static TYPE_OBJECT: LazyStaticType = LazyStaticType::new(); TYPE_OBJECT.get_or_init::(py) diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 19f9c529e95..f1e4100b6e8 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -401,7 +401,7 @@ fn impl_class( const FLAGS: usize = #(#flags)|* | #extended; #[inline] - fn type_object_raw(py: pyo3::Python) -> &'static pyo3::ffi::PyTypeObject { + fn type_object_raw(py: pyo3::Python) -> *mut pyo3::ffi::PyTypeObject { use pyo3::type_object::LazyStaticType; static TYPE_OBJECT: LazyStaticType = LazyStaticType::new(); TYPE_OBJECT.get_or_init::(py) diff --git a/src/freelist.rs b/src/freelist.rs index 2f47c7daefc..2f78e900957 100644 --- a/src/freelist.rs +++ b/src/freelist.rs @@ -72,9 +72,8 @@ where T: PyTypeInfo + PyClassWithFreeList, { unsafe fn new(py: Python, subtype: *mut ffi::PyTypeObject) -> *mut Self::Layout { - let type_obj = Self::type_object_raw(py) as *const _ as _; // if subtype is not equal to this type, we cannot use the freelist - if subtype == type_obj { + if subtype == Self::type_object_raw(py) { if let Some(obj) = ::get_free_list().pop() { ffi::PyObject_Init(obj, subtype); return obj as _; diff --git a/src/pyclass.rs b/src/pyclass.rs index 7fa2ace42c5..796239f41cd 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -18,7 +18,7 @@ pub(crate) unsafe fn default_new( // if the class derives native types(e.g., PyDict), call special new if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE { let base_tp = T::BaseType::type_object_raw(py); - if let Some(base_new) = base_tp.tp_new { + if let Some(base_new) = (*base_tp).tp_new { return base_new(subtype, ptr::null_mut(), ptr::null_mut()); } } @@ -122,7 +122,7 @@ where s => CString::new(s)?.into_raw(), }; - type_object.tp_base = T::BaseType::type_object_raw(py) as *const _ as _; + type_object.tp_base = T::BaseType::type_object_raw(py); type_object.tp_name = match module_name { Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(), diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 51ed4f64059..c83f3f6736a 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -120,7 +120,7 @@ impl PyClassInitializer { T: PyClass, T::BaseLayout: PyBorrowFlagLayout, { - unsafe { self.create_cell_from_subtype(py, T::type_object_raw(py) as *const _ as _) } + unsafe { self.create_cell_from_subtype(py, T::type_object_raw(py)) } } /// Create a new PyCell and initialize it given a typeobject `subtype`. diff --git a/src/type_object.rs b/src/type_object.rs index ea8cc31a6d4..c0ecd888e72 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -101,21 +101,16 @@ pub unsafe trait PyTypeInfo: Sized { type AsRefTarget: crate::PyNativeType; /// PyTypeObject instance for this type. - fn type_object_raw(py: Python) -> &'static ffi::PyTypeObject; + fn type_object_raw(py: Python) -> *mut ffi::PyTypeObject; /// Check if `*mut ffi::PyObject` is instance of this type fn is_instance(object: &PyAny) -> bool { - unsafe { - ffi::PyObject_TypeCheck( - object.as_ptr(), - Self::type_object(object.py()) as *const _ as _, - ) != 0 - } + unsafe { ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object_raw(object.py())) != 0 } } /// Check if `*mut ffi::PyObject` is exact instance of this type fn is_exact_instance(object: &PyAny) -> bool { - unsafe { (*object.as_ptr()).ob_type == Self::type_object(object.py()) as *const _ as _ } + unsafe { (*object.as_ptr()).ob_type == Self::type_object_raw(object.py()) } } } @@ -135,7 +130,7 @@ where T: PyTypeInfo, { fn type_object(py: Python) -> &PyType { - unsafe { py.from_borrowed_ptr(Self::type_object_raw(py) as *const _ as _) } + unsafe { py.from_borrowed_ptr(Self::type_object_raw(py) as _) } } } @@ -143,7 +138,7 @@ where #[doc(hidden)] pub struct LazyStaticType { // Boxed because Python expects the type object to have a stable address. - value: GILOnceCell>, + value: GILOnceCell<*mut ffi::PyTypeObject>, // Threads which have begun initialization. Used for reentrant initialization detection. initializing_threads: Mutex>, } @@ -156,42 +151,38 @@ impl LazyStaticType { } } - pub fn get_or_init(&self, py: Python) -> &ffi::PyTypeObject { - self.value - .get_or_init(py, || { - { - // Code evaluated at class init time, such as class attributes, might lead to - // recursive initalization of the type object if the class attribute is the same - // type as the class. - // - // That could lead to all sorts of unsafety such as using incomplete type objects - // to initialize class instances, so recursive initialization is prevented. - let thread_id = thread::current().id(); - let mut threads = self.initializing_threads.lock(); - if threads.contains(&thread_id) { - panic!("Recursive initialization of type_object for {}", T::NAME); - } else { - threads.push(thread_id) - } + pub fn get_or_init(&self, py: Python) -> *mut ffi::PyTypeObject { + *self.value.get_or_init(py, || { + { + // Code evaluated at class init time, such as class attributes, might lead to + // recursive initalization of the type object if the class attribute is the same + // type as the class. + // + // That could lead to all sorts of unsafety such as using incomplete type objects + // to initialize class instances, so recursive initialization is prevented. + let thread_id = thread::current().id(); + let mut threads = self.initializing_threads.lock(); + if threads.contains(&thread_id) { + panic!("Recursive initialization of type_object for {}", T::NAME); + } else { + threads.push(thread_id) } + } - // Okay, not recursive initialization - can proceed safely. - let mut type_object = Box::new(ffi::PyTypeObject_INIT); + // Okay, not recursive initialization - can proceed safely. + let mut type_object = Box::new(ffi::PyTypeObject_INIT); - initialize_type_object::(py, T::MODULE, type_object.as_mut()).unwrap_or_else( - |e| { - e.print(py); - panic!("An error occurred while initializing class {}", T::NAME) - }, - ); + initialize_type_object::(py, T::MODULE, type_object.as_mut()).unwrap_or_else(|e| { + e.print(py); + panic!("An error occurred while initializing class {}", T::NAME) + }); - // Initialization successfully complete, can clear the thread list. - // (No futher calls to get_or_init() will try to init, on any thread.) - *self.initializing_threads.lock() = Vec::new(); + // Initialization successfully complete, can clear the thread list. + // (No futher calls to get_or_init() will try to init, on any thread.) + *self.initializing_threads.lock() = Vec::new(); - type_object - }) - .as_ref() + Box::into_raw(type_object) + }) } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 6e921a2e6ba..c238e72aec3 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -143,8 +143,11 @@ macro_rules! pyobject_native_type_convert( const MODULE: Option<&'static str> = $module; #[inline] - fn type_object_raw(_py: Python) -> &'static $crate::ffi::PyTypeObject { - unsafe{ &$typeobject } + fn type_object_raw(_py: Python) -> *mut $crate::ffi::PyTypeObject { + // Create a very short lived mutable reference and directly + // cast it to a pointer: no mutable references can be aliasing + // because we hold the GIL. + unsafe { &mut $typeobject } } #[allow(unused_unsafe)]