From a5830cba370a5852cd41c9588e7f5ba86151865c Mon Sep 17 00:00:00 2001 From: Sebastian Puetz Date: Tue, 21 Jul 2020 09:08:51 +0200 Subject: [PATCH] Calculate offsets for weakreflist and dict in PyCell. --- CHANGELOG.md | 2 ++ src/pycell.rs | 16 +++++++++++++++- src/pyclass.rs | 14 +++++--------- src/pyclass_slots.rs | 10 ++++------ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44ec446a009..97d0332c831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027) - Fix segfault with #[pyclass(dict, unsendable)] [#1058](https://github.com/PyO3/pyo3/pull/1058) +- Don't rely on the order of structmembers to compute offsets in PyCell. Related to + [#1058](https://github.com/PyO3/pyo3/pull/1058). [#1059](https://github.com/PyO3/pyo3/pull/1059) ## [0.11.1] - 2020-06-30 ### Added diff --git a/src/pycell.rs b/src/pycell.rs index 94ac61927ec..d4731aaa876 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -8,9 +8,9 @@ use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo use crate::types::PyAny; use crate::{ffi, FromPy, PyErr, PyNativeType, PyObject, PyResult, Python}; use std::cell::{Cell, UnsafeCell}; -use std::fmt; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; +use std::{fmt, mem}; /// Base layout of PyCell. /// This is necessary for sharing BorrowFlag between parents and children. @@ -162,10 +162,24 @@ impl PyCellInner { pub struct PyCell { inner: PyCellInner, thread_checker: T::ThreadChecker, + // DO NOT CHANGE THE ORDER OF THESE FIELDS WITHOUT CHANGING PyCell::dict_offset() + // AND PyCell::weakref_offset() dict: T::Dict, weakref: T::WeakRef, } +impl PyCell { + /// Get the offset of the dictionary from the start of the struct in bytes. + pub(crate) fn dict_offset() -> usize { + mem::size_of::() - mem::size_of::() - mem::size_of::() + } + + /// Get the offset of the weakref list from the start of the struct in bytes. + pub(crate) fn weakref_offset() -> usize { + mem::size_of::() - mem::size_of::() + } +} + unsafe impl PyNativeType for PyCell {} impl PyCell { diff --git a/src/pyclass.rs b/src/pyclass.rs index b6b05f86c61..2c224a217ec 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -137,18 +137,14 @@ where // type size type_object.tp_basicsize = std::mem::size_of::() as ffi::Py_ssize_t; - let mut offset = type_object.tp_basicsize; - // __dict__ support - if let Some(dict_offset) = T::Dict::OFFSET { - offset += dict_offset as ffi::Py_ssize_t; - type_object.tp_dictoffset = offset; + if !T::Dict::IS_DUMMY { + type_object.tp_dictoffset = PyCell::::dict_offset() as ffi::Py_ssize_t; } // weakref support - if let Some(weakref_offset) = T::WeakRef::OFFSET { - offset += weakref_offset as ffi::Py_ssize_t; - type_object.tp_weaklistoffset = offset; + if !T::WeakRef::IS_DUMMY { + type_object.tp_weaklistoffset = PyCell::::weakref_offset() as ffi::Py_ssize_t; } // GC support @@ -206,7 +202,7 @@ where // properties let mut props = py_class_properties::(); - if T::Dict::OFFSET.is_some() { + if !T::Dict::IS_DUMMY { props.push(ffi::PyGetSetDef_DICT); } if !props.is_empty() { diff --git a/src/pyclass_slots.rs b/src/pyclass_slots.rs index 539e630e3eb..a5ba8093129 100644 --- a/src/pyclass_slots.rs +++ b/src/pyclass_slots.rs @@ -2,11 +2,9 @@ //! Mainly used by our proc-macro codes. use crate::{ffi, Python}; -const POINTER_SIZE: isize = std::mem::size_of::<*mut ffi::PyObject>() as _; - /// Represents `__dict__` field for `#[pyclass]`. pub trait PyClassDict { - const OFFSET: Option = None; + const IS_DUMMY: bool = true; fn new() -> Self; unsafe fn clear_dict(&mut self, _py: Python) {} private_decl! {} @@ -14,7 +12,7 @@ pub trait PyClassDict { /// Represents `__weakref__` field for `#[pyclass]`. pub trait PyClassWeakRef { - const OFFSET: Option = None; + const IS_DUMMY: bool = true; fn new() -> Self; unsafe fn clear_weakrefs(&mut self, _obj: *mut ffi::PyObject, _py: Python) {} private_decl! {} @@ -45,7 +43,7 @@ pub struct PyClassDictSlot(*mut ffi::PyObject); impl PyClassDict for PyClassDictSlot { private_impl! {} - const OFFSET: Option = Some(-POINTER_SIZE); + const IS_DUMMY: bool = false; fn new() -> Self { Self(std::ptr::null_mut()) } @@ -64,7 +62,7 @@ pub struct PyClassWeakRefSlot(*mut ffi::PyObject); impl PyClassWeakRef for PyClassWeakRefSlot { private_impl! {} - const OFFSET: Option = Some(-POINTER_SIZE); + const IS_DUMMY: bool = false; fn new() -> Self { Self(std::ptr::null_mut()) }