Skip to content

Commit 22b998f

Browse files
committed
Clarify semantics of size-preserving tranasmutes
Makes progress on #2701, #1940, #1852 gherrit-pr-id: G64ec124d566c828ea61e6edf831a10338aa4c879
1 parent 6aae3de commit 22b998f

File tree

1 file changed

+33
-39
lines changed

1 file changed

+33
-39
lines changed

src/pointer/transmute.rs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::{
3535
///
3636
/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is
3737
/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a,
38-
/// Dst, (A, Unaligned, DV)>` by preserving pointer address and metadata.
38+
/// Dst, (A, Unaligned, DV)>` using `<Dst as SizeEq<Src>>::CastFrom::project`.
3939
///
4040
/// ## Pre-conditions
4141
///
@@ -49,7 +49,10 @@ use crate::{
4949
/// `Src`s
5050
/// - Reverse transmutation: Either of the following hold:
5151
/// - `dst` does not permit mutation of its referent
52-
/// - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s
52+
/// - The set of `DV`-valid referents of `dst` is a subset of the set of
53+
/// `SV`-valid referents of `src` (NOTE: this condition effectively bans
54+
/// shrinking or overwriting transmutes, which cannot satisfy this
55+
/// condition)
5356
/// - No safe code, given access to `src` and `dst`, can cause undefined
5457
/// behavior: Any of the following hold:
5558
/// - `A` is `Exclusive`
@@ -64,30 +67,17 @@ use crate::{
6467
/// - `src`'s referent is `DV`-valid for `Dst`
6568
/// - `Dst: SizeEq<Src>`
6669
///
67-
/// We are trying to prove that it is sound to perform a pointer address- and
68-
/// metadata-preserving transmute from `src` to a `dst: Ptr<'a, Dst, (A,
70+
/// We are trying to prove that it is sound to cast using `<Dst as
71+
/// SizeEq<Src>>::CastFrom::project` from `src` to a `dst: Ptr<'a, Dst, (A,
6972
/// Unaligned, DV)>`. We need to prove that such a transmute does not violate
7073
/// any of `src`'s invariants, and that it satisfies all invariants of the
7174
/// destination `Ptr` type.
7275
///
73-
/// First, all of `src`'s `PtrInner` invariants are upheld. `src`'s address and
74-
/// metadata are unchanged, so:
75-
/// - If its referent is not zero sized, then it still has valid provenance for
76-
/// its referent, which is still entirely contained in some Rust allocation,
77-
/// `A`
78-
/// - If its referent is not zero sized, `A` is guaranteed to live for at least
79-
/// `'a`
76+
/// First, by invariant on `SizeEq`, `src`'s address is unchanged, so it still
77+
/// satisfies its alignment. Since `dst`'s alignment is `Unaligned`, it
78+
/// trivially satisfies its alignment.
8079
///
81-
/// Since `Dst: SizeEq<Src>`, and since `dst` has the same address and metadata
82-
/// as `src`, `dst` addresses the same byte range as `src`. `dst` also has the
83-
/// same lifetime as `src`. Therefore, all of the `PtrInner` invariants
84-
/// mentioned above also hold for `dst`.
85-
///
86-
/// Second, since `src`'s address is unchanged, it still satisfies its
87-
/// alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies
88-
/// its alignment.
89-
///
90-
/// Third, aliasing is either `Exclusive` or `Shared`:
80+
/// Second, aliasing is either `Exclusive` or `Shared`:
9181
/// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive`
9282
/// aliasing trivially: since `src` and `dst` have the same lifetime, `src` is
9383
/// inaccessible so long as `dst` is alive, and no other live `Ptr`s or
@@ -98,15 +88,15 @@ use crate::{
9888
/// - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst`
9989
/// pointing to the same byte range at the same time.
10090
///
101-
/// Fourth, `src`'s validity is satisfied. By invariant, `src`'s referent began
91+
/// Third, `src`'s validity is satisfied. By invariant, `src`'s referent began
10292
/// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the
10393
/// following hold:
10494
/// - `dst` does not permit mutation of its referent.
105-
/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
106-
/// `Src`s. Thus, any value written via `dst` is guaranteed to be `SV`-valid
107-
/// for `Src`.
95+
/// - The set of `DV`-valid referents of `dst` is a subset of the set of
96+
/// `SV`-valid referents of `src`. Thus, any value written via `dst` is
97+
/// guaranteed to be an `SV`-valid referent of `src`.
10898
///
109-
/// Fifth, `dst`'s validity is satisfied. It is a given of this proof that the
99+
/// Fourth, `dst`'s validity is satisfied. It is a given of this proof that the
110100
/// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either
111101
/// of the following hold:
112102
/// - So long as `dst` is active, no mutation of the referent is allowed except
@@ -134,9 +124,11 @@ pub enum BecauseMutationCompatible {}
134124
// - `Dst: TransmuteFrom<Src, SV, DV>`. Since `Dst: SizeEq<Src>`, this bound
135125
// guarantees that the set of `DV`-valid `Dst`s is a supserset of the set of
136126
// `SV`-valid `Src`s.
137-
// - Reverse transmutation: `Src: TransmuteFrom<Dst, DV, SV>`. Since `Dst:
138-
// SizeEq<Src>`, this guarantees that the set of `DV`-valid `Dst`s is a subset
139-
// of the set of `SV`-valid `Src`s.
127+
// - Reverse transmutation: Since the underlying cast is performed using `<Dst
128+
// as SizeEq<Src>>::CastFrom::project`, `dst` addresses the same bytes as
129+
// `src`. By `Src: TransmuteFrom<Dst, DV, SV>`, the set of `DV`-valid `Dst`s
130+
// is a subset of the set of `SV`-valid `Src`s. Thus, the set of `DV`-valid
131+
// referents of `dst` is a subset of the set of `SV`-valid referents of `src`.
140132
// - No safe code, given access to `src` and `dst`, can cause undefined
141133
// behavior: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, at least one of
142134
// the following holds:
@@ -287,18 +279,20 @@ where
287279
/// DV>` conveys no safety guarantee.
288280
pub unsafe trait TransmuteFrom<Src: ?Sized, SV, DV> {}
289281

282+
/// Carries the ability to perform a size-preserving cast or conversion from a
283+
/// raw pointer to `Src` to a raw pointer to `Self`.
284+
///
285+
/// The cast/conversion is carried by the associated [`CastFrom`] type, and
286+
/// may be a no-op cast (without updating pointer metadata) or a conversion
287+
/// which updates pointer metadata.
288+
///
290289
/// # Safety
291290
///
292-
/// `T` and `Self` must have the same vtable kind (`Sized`, slice DST, `dyn`,
293-
/// etc) and have the same size. In particular:
294-
/// - If `T: Sized` and `Self: Sized`, then their sizes must be equal
295-
/// - If `T: ?Sized` and `Self: ?Sized`, then `Self::CastFrom` must be a
296-
/// size-preserving cast. *Note that it is **not** guaranteed that an `as`
297-
/// cast preserves referent size: it may be the case that `Self::CastFrom`
298-
/// modifies the pointer's metadata in order to preserve referent size, which
299-
/// an `as` cast does not do.*
300-
pub unsafe trait SizeEq<T: ?Sized> {
301-
type CastFrom: cast::Cast<T, Self>;
291+
/// The associated [`CastFrom`] must preserve referent size.
292+
///
293+
/// [`CastFrom`]: SizeEq::CastFrom
294+
pub unsafe trait SizeEq<Src: ?Sized> {
295+
type CastFrom: cast::Cast<Src, Self>;
302296
}
303297

304298
// SAFETY: `T` trivially has the same size and vtable kind as `T`, and since

0 commit comments

Comments
 (0)