-
Notifications
You must be signed in to change notification settings - Fork 778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix UB in *_offset functions #2450
Conversation
I suspect it had been considered when this code was written, but isn't |
FWIW I suspect the real reason that |
It is thus as fine as it could possibly be. The current PR duplicates a structure's layout, which means these could theoretically end up out of sync as the codebase is updated, which in a vacuum (I don't know the constraints of PyO3), seems orders of magnitude more error-prone than using an unofficial Rust implementation with no One approach to make the code robust to original struct updates, while keeping the current interesting strategy, would be: type Apply<Wrapper, T> = <Wrapper as CanWrap<T>>::T;
trait CanWrap<T> : 'static { type T; }
/// For any `T`, `Apply<Identity, T> = T`.
enum Identity {}
impl<T> CanWrap<T> for Identity { type T = T; }
/// For any `T`, `Apply<InManuallyDrop, T> = ManuallyDrop<T>`
enum InManuallyDrop {}
impl<T> CanWrap<T> for InManuallyDrop { type T = ManuallyDrop<T>; }
#[repr(C)]
pub(crate) struct PyCellContents<T: PyClassImpl, Wrapper = Identity>
where
// this would not be needed if we had (type) GATs
Wrapper : CanWrap< ManuallyDrop<UnsafeCell<T>> >,
Wrapper : CanWrap< <T::PyClassMutability as PyClassMutability>::Storage >,
Wrapper : CanWrap< T::ThreadChecker >,
Wrapper : CanWrap< T::Dict >,
Wrapper : CanWrap< T::WeakRef >,
{
pub(crate) value: Apply<Wrapper, ManuallyDrop<UnsafeCell<T> >,
pub(crate) borrow_checker: Apply<Wrapper, <T::PyClassMutability as PyClassMutability>::Storage >,
pub(crate) thread_checker: Apply<Wrapper, T::ThreadChecker >,
pub(crate) dict: Apply<Wrapper, T::Dict >,
pub(crate) weakref: Apply<Wrapper, T::WeakRef >,
} that way, the
|
Hmm, I like simple, and just using memoffset sounds simple. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, using memoffset
sounds reasonable to me. Please add a CHANGELOG entry. Not sure whether this classes as Packaging
or Fixed
category.
Thanks for cleaning up the tests with flaky type inference issues too! 😁
@@ -17,6 +17,7 @@ edition = "2018" | |||
cfg-if = "1.0" | |||
libc = "0.2.62" | |||
parking_lot = ">= 0.11, < 0.13" | |||
memoffset = "0.6.5" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add a note here that it's to support safe offset calculations on versions predating addr_of
? I imagine in the future we might consider removing again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are using it to compute offsets in all cases since even when addr_of
is available, using memoffset
enables us to avoid writing out its usage ourselves.
Personally, I think as it takes care of what is available where and how to use it, memoffset
does carry its weight as a dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with this, I was thinking more that after a future MSRV bump that may change as addr_of
would be trivial for us to implement safely. I'll worry about that in the future, perhaps 😄
If the
addr_of
macro is not available, this created a zeroedPyCell<T>
, but arbitraryT
's do not permit zero-initialization.