Skip to content

Commit a8cd070

Browse files
committed
Add more safety proof to KnownLayout derive
Makes progress on #429
1 parent 1c77a9d commit a8cd070

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

src/lib.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -785,24 +785,16 @@ unsafe impl<T> KnownLayout for [T] {
785785
let slc = unsafe { &*slc };
786786

787787
// This is correct because the preceding `as` cast preserves the number
788-
// of slice elements. Per
789-
// https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast:
788+
// of slice elements. [1]
789+
//
790+
// [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast:
790791
//
791792
// For slice types like `[T]` and `[U]`, the raw pointer types `*const
792793
// [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode the number of
793794
// elements in this slice. Casts between these raw pointer types
794-
// preserve the number of elements. Note that, as a consequence, such
795-
// casts do *not* necessarily preserve the size of the pointer's
796-
// referent (e.g., casting `*const [u16]` to `*const [u8]` will result
797-
// in a raw pointer which refers to an object of half the size of the
798-
// original). The same holds for `str` and any compound type whose
799-
// unsized tail is a slice type, such as struct `Foo(i32, [u8])` or
800-
// `(u64, Foo)`.
801-
//
802-
// TODO(#429),
803-
// TODO(https://github.com/rust-lang/reference/pull/1417): Once this
804-
// text is available on the Stable docs, cite those instead of the
805-
// Nightly docs.
795+
// preserve the number of elements. ... The same holds for `str` and
796+
// any compound type whose unsized tail is a slice type, such as
797+
// struct `Foo(i32, [u8])` or `(u64, Foo)`.
806798
slc.len()
807799
}
808800
}

zerocopy-derive/src/lib.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,34 @@ fn derive_known_layout_inner(ast: &DeriveInput) -> proc_macro2::TokenStream {
191191
};
192192

193193
// SAFETY:
194-
// - The recursive call to `raw_from_ptr_len` preserves both address and provenance.
195-
// - The `as` cast preserves both address and provenance.
196-
// - `NonNull::new_unchecked` preserves both address and provenance.
194+
// - The returned pointer has the same address and provenance as
195+
// `bytes`:
196+
// - The recursive call to `raw_from_ptr_len` preserves both
197+
// address and provenance.
198+
// - The `as` cast preserves both address and provenance.
199+
// - `NonNull::new_unchecked` preserves both address and
200+
// provenance.
201+
// - If `Self` is a slice DST, the returned pointer encodes
202+
// `elems` elements in the trailing slice:
203+
// - This is true of the recursive call to `raw_from_ptr_len`.
204+
// - `trailing.as_ptr() as *mut Self` preserves trailing slice
205+
// element count [1].
206+
// - `NonNull::new_unchecked` preserves trailing slice element
207+
// count.
208+
//
209+
// [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast:
210+
//
211+
// `*const T`` / `*mut T` can be cast to `*const U` / `*mut U`
212+
// with the following behavior:
213+
// ...
214+
// - If `T` and `U` are both unsized, the pointer is also
215+
// returned unchanged. In particular, the metadata is
216+
// preserved exactly.
217+
//
218+
// For instance, a cast from `*const [T]` to `*const [U]`
219+
// preserves the number of elements. ... The same holds
220+
// for str and any compound type whose unsized tail is a
221+
// slice type, such as struct `Foo(i32, [u8])` or `(u64, Foo)`.
197222
#[inline(always)]
198223
fn raw_from_ptr_len(
199224
bytes: ::zerocopy::macro_util::core_reexport::ptr::NonNull<u8>,

0 commit comments

Comments
 (0)