-
Notifications
You must be signed in to change notification settings - Fork 121
Description
Summary
Introduce a Immutable
trait which indicates that a type contains no UnsafeCell
s. Allow FromZeros
, FromBytes
, and AsBytes
on types with UnsafeCell
s and use Immutable
as a bound on individual methods/functions.
This enables by-value transmutations such as transmute!
on types containing UnsafeCell
s.
See also #694.
Progress
- Add
Immutable
traitTo pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Allow deriving
Immutable
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Allow
FromZeros
,FromBytes
, andAsBytes
onUnsafeCell
; addImmutable
bound on methods as neededTo pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Implement
TryFromBytes
,FromZeros
, andFromBytes
for unsizedUnsafeCell
. See the discussion below for why we originally limited these impls to sizedUnsafeCell
s only.To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Allow
TryFromBytes
onUnsafeCell
; addImmutable
bound ontry_from_ref
methodTo pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Remove
#[doc(hidden)]
fromImmutable
andpub use zerocopy_derive::Immutable
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. - Consider renaming to be consistent with whatever name Rust chooses for what is currently called Freeze since we will likely treat
Immutable
as merely a polyfill for that trait - Loosen documentation to promise only "no interior mutability" (TODO: how do we define this formally?) and say that it is sufficient to prove that a type (recursively) contains no
UnsafeCell
s, but not necessary, and that callers cannot assume thatT: Immutable
implies thatT
contains noUnsafeCell
s. Note that our code will need to rely on this implication, and all safety comments should be updated to point at an issue that tracks this change. - Non-breaking changes
Consider adding blanket traits:RefFromZeros
forFromZeros + Immutable
,RefFromBytes
forFromBytes + Immutable
, andRefAsBytes
forAsBytes + Immutable
- We've decided not to do this
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Details
We require that FromZeros
, FromBytes
, and AsBytes
types don't permit interior mutability. This is a requirement in order for reference casts (e.g., &T
to &[u8]
or vice-versa) to be valid, but is not a requirement for value casts. As a result, we don't support some transmutations that are sound (namely, value transmutations on types with interior mutability).
If we added a separate Immutable
trait to describe this "has no UnsafeCell
s" property, then we could decouple it from the other traits and allow them to support types with UnsafeCell
s. Immutable
would then be required as a bound on some functions/methods/macros. This would make our API somewhat more complicated, but would unlock a new class of use cases.
Note that Immutable
would be equivalent to the stdlib-internal Freeze
trait. There is a proposal to make that trait public, but we shouldn't bank on that happening any time soon.
TryFromBytes
and unsized UnsafeCell
In principle, there's no reason we couldn't implement FromZeros
, FromBytes
, and AsBytes
for UnsafeCell<T>
even when T: ?Sized
. However, this would not play nicely with TryFromBytes
(currently in progress in #5), which we want to eventually be a super-trait of FromZeros
.
In particular, in order to implement TryFromBytes
for a type, we have to implement the is_bit_valid
method. For UnsafeCell<T>
where T: Sized
, we can make a copy of the referent UnsafeCell<T>
, transmute it to a MaybeUninit<T>
, and then construct a Ptr<T>
to that value. This workaround isn't possible for unsized UnsafeCell
s.
Given that the whole problem with UnsafeCell
s arises when they're handled by-reference, and given that the only way to operate on unsized values in Rust (at least today) is by reference, supporting unsized UnsafeCell
s is unlikely to be useful to any of our users. Thus, by implementing TryFromBytes
(and, by implication, the other traits) only for sized UnsafeCell
, we get most of the benefit.
Motivation
This was originally motivated by chipsalliance/caliptra-sw#634. @korran has provided this minimized example to motivate the feature request:
#[repr(C)]
pub struct Prng {
// It is critical for safety that every bit-pattern of this struct
// is valid (no padding, no enums, no references), similar to the requirements for
// zerocopy::FromBytes.
s0: Cell<u32>,
s1: Cell<u32>,
s2: Cell<u32>,
s3: Cell<u32>,
}
impl Prng {
/// # Safety
///
/// Caller must verify that the memory locations between `addr` and
/// `addr + size_of::<Prng>()` are valid and meet the alignment
/// requirements of Prng, and are not used for anything else.
pub unsafe fn from_address(addr: u32) -> &'static Self {
&*(addr as *const Self)
}
pub fn next(&self) -> u32 { ... }
}
If FromBytes
didn't forbid interior mutability, the API of from_address
would be the same, but it would not require the authors of from_address
to justify that it's sound to construct a Prng
at the given memory location regardless of its previous contents. Instead, the safety argument can just be "Prng: FromBytes
, so it's sound regardless of the memory contents".
Activity
std::marker::Freeze
pub again rust-lang/rust#60715UnsafeCell
#352FromBytes for MaybeUninit<T>
? #310[-]Consider separating `FromBytes` and `RefFromBytes` (and same for `AsBytes`)[/-][+]Consider separating `FromBytes` and `RefFromBytes` (and same for `AsBytes`) or supporting `NoCell`[/+]Initial commit of NoCell
Initial commit of NoCell
NoCell
#656Initial commit of NoCell
Initial commit of NoCell
Initial commit of NoCell
56 remaining items
Remove more unnecessary `Immutable` bounds from `FromBytes` (#1236)
[-]Separate "no `UnsafeCell`" property into separate `NoCell` trait; allow `FromZeros`, `FromBytes`, and `AsBytes` on types with `UnsafeCell`s[/-][+]Separate "no `UnsafeCell`" property into separate `Immutable` trait; allow `FromZeros`, `FromBytes`, and `AsBytes` on types with `UnsafeCell`s[/+]Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell
Implement TryFromBytes for unsized UnsafeCell (#1619)
joshlf commentedon Oct 6, 2024
@korran This is now available stably in our 0.8 release train.
joshlf commentedon Oct 6, 2024
The sole remaining concern is now in its own issue:
Immutable
#1296