Skip to content

Commit 09a6d35

Browse files
committed
[WIP] Use ReadOnly in is_bit_valid
gherrit-pr-id: G7691845b6b02e9f3d9578435d732bacfa6ca674f
1 parent ee75641 commit 09a6d35

14 files changed

Lines changed: 484 additions & 249 deletions

File tree

src/impls.rs

Lines changed: 78 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ assert_unaligned!(bool);
108108
// pattern 0x01.
109109
const _: () = unsafe {
110110
unsafe_impl!(=> TryFromBytes for bool; |byte| {
111-
let byte = byte.transmute::<u8, invariant::Valid, _>();
111+
let byte = byte.transmute::<u8, invariant::Valid, BecauseImmutable>();
112112
*byte.unaligned_as_ref() < 2
113113
})
114114
};
115-
impl_size_eq!(bool, u8);
115+
impl_size_eq!(=> bool, u8);
116116

117117
// SAFETY:
118118
// - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.
@@ -138,13 +138,13 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
138138
// `char`.
139139
const _: () = unsafe {
140140
unsafe_impl!(=> TryFromBytes for char; |c| {
141-
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
141+
let c = c.transmute::<Unalign<u32>, invariant::Valid, BecauseImmutable>();
142142
let c = c.read_unaligned().into_inner();
143143
char::from_u32(c).is_some()
144144
});
145145
};
146146

147-
impl_size_eq!(char, Unalign<u32>);
147+
impl_size_eq!(=> char, Unalign<u32>);
148148

149149
// SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.
150150
// - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.
@@ -173,21 +173,21 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig
173173
// Returns `Err` if the slice is not UTF-8.
174174
const _: () = unsafe {
175175
unsafe_impl!(=> TryFromBytes for str; |c| {
176-
let c = c.transmute::<[u8], invariant::Valid, _>();
176+
let c = c.transmute::<[u8], invariant::Valid, BecauseImmutable>();
177177
let c = c.unaligned_as_ref();
178178
core::str::from_utf8(c).is_ok()
179179
})
180180
};
181181

182-
impl_size_eq!(str, [u8]);
182+
impl_size_eq!(=> str, [u8]);
183183

184184
macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
185185
($($nonzero:ident[$prim:ty]),*) => {
186186
$(
187187
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
188-
impl_size_eq!($nonzero, Unalign<$prim>);
188+
impl_size_eq!(=> $nonzero, Unalign<$prim>);
189189

190-
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
190+
let n = n.transmute::<Unalign<$prim>, invariant::Valid, BecauseImmutable>();
191191
$nonzero::new(n.read_unaligned().into_inner()).is_some()
192192
});
193193
)*
@@ -403,13 +403,23 @@ const _: () = unsafe {
403403
mod atomics {
404404
use super::*;
405405

406-
macro_rules! impl_traits_for_atomics {
407-
($($atomics:ident [$primitives:ident]),* $(,)?) => {
406+
macro_rules! impl_layout_traits_for_atomics {
407+
($($($tyvar:ident)? => $atomics:ty [$primitives:ty]),* $(,)?) => {
408+
$(
409+
impl_known_layout!($($tyvar => )? $atomics);
410+
411+
impl_size_eq!($($tyvar)? => $atomics, $primitives);
412+
impl_size_eq!($($tyvar)? => $atomics, UnsafeCell<$primitives>);
413+
)*
414+
};
415+
}
416+
417+
macro_rules! impl_validity_traits_for_atomics {
418+
($($atomics:tt [$primitives:ty]),* $(,)?) => {
408419
$(
409-
impl_known_layout!($atomics);
410-
impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]);
411420
impl_for_transmute_from!(=> FromZeros for $atomics [UnsafeCell<$primitives>]);
412421
impl_for_transmute_from!(=> FromBytes for $atomics [UnsafeCell<$primitives>]);
422+
impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]);
413423
impl_for_transmute_from!(=> IntoBytes for $atomics [UnsafeCell<$primitives>]);
414424
)*
415425
};
@@ -425,8 +435,7 @@ mod atomics {
425435
($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{
426436
crate::util::macros::__unsafe();
427437

428-
use core::cell::UnsafeCell;
429-
use crate::pointer::{SizeEq, TransmuteFrom, invariant::Valid};
438+
use crate::pointer::{TransmuteFrom, invariant::Valid};
430439

431440
$(
432441
// SAFETY: The caller promised that `$atomic` and `$prim` have
@@ -436,18 +445,18 @@ mod atomics {
436445
// the same size and bit validity.
437446
unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {}
438447

439-
impl<$($tyvar)?> SizeEq<$atomic> for $prim {
440-
type CastFrom = $crate::pointer::cast::CastSizedExact;
441-
}
442-
impl<$($tyvar)?> SizeEq<$prim> for $atomic {
443-
type CastFrom = $crate::pointer::cast::CastSizedExact;
444-
}
445-
impl<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> {
446-
type CastFrom = $crate::pointer::cast::CastSizedExact;
447-
}
448-
impl<$($tyvar)?> SizeEq<UnsafeCell<$prim>> for $atomic {
449-
type CastFrom = $crate::pointer::cast::CastSizedExact;
450-
}
448+
// impl<$($tyvar)?> SizeEq<$atomic> for $prim {
449+
// type CastFrom = $crate::pointer::cast::CastSizedExact;
450+
// }
451+
// impl<$($tyvar)?> SizeEq<$prim> for $atomic {
452+
// type CastFrom = $crate::pointer::cast::CastSizedExact;
453+
// }
454+
// impl<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> {
455+
// type CastFrom = $crate::pointer::cast::CastSizedExact;
456+
// }
457+
// impl<$($tyvar)?> SizeEq<UnsafeCell<$prim>> for $atomic {
458+
// type CastFrom = $crate::pointer::cast::CastSizedExact;
459+
// }
451460

452461
// SAFETY: The caller promised that `$atomic` and `$prim` have
453462
// the same bit validity. `UnsafeCell<T>` has the same bit
@@ -472,12 +481,11 @@ mod atomics {
472481

473482
use super::*;
474483

475-
impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
476-
477-
impl_known_layout!(AtomicBool);
484+
impl_layout_traits_for_atomics!(=> AtomicBool [bool], => AtomicU8[u8], => AtomicI8[i8]);
485+
impl_validity_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
478486

479-
impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell<bool>]);
480487
impl_for_transmute_from!(=> FromZeros for AtomicBool [UnsafeCell<bool>]);
488+
impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell<bool>]);
481489
impl_for_transmute_from!(=> IntoBytes for AtomicBool [UnsafeCell<bool>]);
482490

483491
// SAFETY: Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the
@@ -539,7 +547,8 @@ mod atomics {
539547

540548
use super::*;
541549

542-
impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);
550+
impl_layout_traits_for_atomics!(=> AtomicU16[u16], => AtomicI16[i16]);
551+
impl_validity_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);
543552

544553
// SAFETY: `AtomicU16` and `AtomicI16` have the same size and bit
545554
// validity as `u16` and `i16` respectively [1][2].
@@ -566,7 +575,8 @@ mod atomics {
566575

567576
use super::*;
568577

569-
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
578+
impl_layout_traits_for_atomics!(=> AtomicU32[u32], => AtomicI32[i32]);
579+
impl_validity_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
570580

571581
// SAFETY: `AtomicU32` and `AtomicI32` have the same size and bit
572582
// validity as `u32` and `i32` respectively [1][2].
@@ -593,7 +603,8 @@ mod atomics {
593603

594604
use super::*;
595605

596-
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
606+
impl_layout_traits_for_atomics!(=> AtomicU64[u64], => AtomicI64[i64]);
607+
impl_validity_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
597608

598609
// SAFETY: `AtomicU64` and `AtomicI64` have the same size and bit
599610
// validity as `u64` and `i64` respectively [1][2].
@@ -620,9 +631,8 @@ mod atomics {
620631

621632
use super::*;
622633

623-
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
624-
625-
impl_known_layout!(T => AtomicPtr<T>);
634+
impl_layout_traits_for_atomics!(T => AtomicPtr<T> [*mut T], => AtomicUsize[usize], => AtomicIsize[isize]);
635+
impl_validity_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
626636

627637
// FIXME(#170): Implement `FromBytes` and `IntoBytes` once we implement
628638
// those traits for `*mut T`.
@@ -851,29 +861,30 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
851861
}
852862

853863
#[inline]
854-
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool {
855-
// The only way to implement this function is using an exclusive-aliased
856-
// pointer. `UnsafeCell`s cannot be read via shared-aliased pointers
857-
// (other than by using `unsafe` code, which we can't use since we can't
858-
// guarantee how our users are accessing or modifying the `UnsafeCell`).
859-
//
860-
// `is_bit_valid` is documented as panicking or failing to monomorphize
861-
// if called with a shared-aliased pointer on a type containing an
862-
// `UnsafeCell`. In practice, it will always be a monomorphization error.
863-
// Since `is_bit_valid` is `#[doc(hidden)]` and only called directly
864-
// from this crate, we only need to worry about our own code incorrectly
865-
// calling `UnsafeCell::is_bit_valid`. The post-monomorphization error
866-
// makes it easier to test that this is truly the case, and also means
867-
// that if we make a mistake, it will cause downstream code to fail to
868-
// compile, which will immediately surface the mistake and give us a
869-
// chance to fix it quickly.
870-
let c = candidate.into_exclusive_or_pme();
871-
872-
// SAFETY: Since `UnsafeCell<T>` and `T` have the same layout and bit
873-
// validity, `UnsafeCell<T>` is bit-valid exactly when its wrapped `T`
874-
// is. Thus, this is a sound implementation of
875-
// `UnsafeCell::is_bit_valid`.
876-
T::is_bit_valid(c.get_mut())
864+
fn is_bit_valid(candidate: Maybe<'_, Self>) -> bool {
865+
T::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
866+
// // The only way to implement this function is using an exclusive-aliased
867+
// // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers
868+
// // (other than by using `unsafe` code, which we can't use since we can't
869+
// // guarantee how our users are accessing or modifying the `UnsafeCell`).
870+
// //
871+
// // `is_bit_valid` is documented as panicking or failing to monomorphize
872+
// // if called with a shared-aliased pointer on a type containing an
873+
// // `UnsafeCell`. In practice, it will always be a monomorphization error.
874+
// // Since `is_bit_valid` is `#[doc(hidden)]` and only called directly
875+
// // from this crate, we only need to worry about our own code incorrectly
876+
// // calling `UnsafeCell::is_bit_valid`. The post-monomorphization error
877+
// // makes it easier to test that this is truly the case, and also means
878+
// // that if we make a mistake, it will cause downstream code to fail to
879+
// // compile, which will immediately surface the mistake and give us a
880+
// // chance to fix it quickly.
881+
// let c = candidate.into_exclusive_or_pme();
882+
883+
// // SAFETY: Since `UnsafeCell<T>` and `T` have the same layout and bit
884+
// // validity, `UnsafeCell<T>` is bit-valid exactly when its wrapped `T`
885+
// // is. Thus, this is a sound implementation of
886+
// // `UnsafeCell::is_bit_valid`.
887+
// T::is_bit_valid(c.get_mut())
877888
}
878889
}
879890

@@ -902,11 +913,15 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
902913
const _: () = unsafe {
903914
unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]);
904915
unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c| {
916+
let c: Ptr<'_, [ReadOnly<T>; N], _> = c.cast::<_, crate::pointer::cast::CastSized, _>();
917+
let c: Ptr<'_, [ReadOnly<T>], _> = c.as_slice();
918+
let c: Ptr<'_, ReadOnly<[T]>, _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
919+
905920
// Note that this call may panic, but it would still be sound even if it
906921
// did. `is_bit_valid` does not promise that it will not panic (in fact,
907922
// it explicitly warns that it's a possibility), and we have not
908923
// violated any safety invariants that we must fix before returning.
909-
<[T] as TryFromBytes>::is_bit_valid(c.as_slice())
924+
<[T] as TryFromBytes>::is_bit_valid(c)
910925
});
911926
unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
912927
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
@@ -915,6 +930,8 @@ const _: () = unsafe {
915930
assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
916931
unsafe_impl!(T: Immutable => Immutable for [T]);
917932
unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c| {
933+
let c: Ptr<'_, [ReadOnly<T>], _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
934+
918935
// SAFETY: Per the reference [1]:
919936
//
920937
// An array of `[T; N]` has a size of `size_of::<T>() * N` and the
@@ -1146,6 +1163,7 @@ mod tests {
11461163
use super::*;
11471164
use crate::pointer::invariant;
11481165

1166+
#[cfg(never)]
11491167
#[test]
11501168
fn test_impls() {
11511169
// A type that can supply test cases for testing

src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,8 @@ const _: () = unsafe {
11031103
pub const STRUCT_VARIANT_ID: i128 = -1;
11041104
#[doc(hidden)]
11051105
pub const UNION_VARIANT_ID: i128 = -2;
1106+
#[doc(hidden)]
1107+
pub const REPR_C_UNION_VARIANT_ID: i128 = -3;
11061108

11071109
/// Projects a given field from `Self`.
11081110
///
@@ -1566,7 +1568,7 @@ pub unsafe trait TryFromBytes {
15661568
/// [`UnsafeCell`]: core::cell::UnsafeCell
15671569
/// [`Shared`]: invariant::Shared
15681570
#[doc(hidden)]
1569-
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool;
1571+
fn is_bit_valid(candidate: Maybe<'_, Self>) -> bool;
15701572

15711573
/// Attempts to interpret the given `source` as a `&Self`.
15721574
///
@@ -2974,7 +2976,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
29742976
// via `c_ptr` so long as it is live, so we don't need to worry about the
29752977
// fact that `c_ptr` may have more restricted validity than `candidate`.
29762978
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
2977-
let c_ptr = c_ptr.transmute();
2979+
let mut c_ptr = c_ptr.cast::<_, crate::pointer::cast::CastSized, _>();
29782980

29792981
// Since we don't have `T: KnownLayout`, we hack around that by using
29802982
// `Wrapping<T>`, which implements `KnownLayout` even if `T` doesn't.
@@ -2987,7 +2989,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
29872989
// `try_into_valid` (and thus `is_bit_valid`) with a shared pointer when
29882990
// `Self: !Immutable`. Since `Self: Immutable`, this panic condition will
29892991
// not happen.
2990-
if !Wrapping::<T>::is_bit_valid(c_ptr.forget_aligned()) {
2992+
if !Wrapping::<T>::is_bit_valid(c_ptr.reborrow_shared().forget_aligned()) {
29912993
return Err(ValidityError::new(source).into());
29922994
}
29932995

src/macros.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,8 @@ macro_rules! cryptocorrosion_derive_traits {
895895
$($field_ty: $crate::FromBytes,)*
896896
)?
897897
{
898-
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
899-
where
900-
A: $crate::pointer::invariant::Reference
901-
{
898+
#[inline]
899+
fn is_bit_valid(_c: $crate::Maybe<'_, Self>) -> bool {
902900
// SAFETY: This macro only accepts `#[repr(C)]` and
903901
// `#[repr(transparent)]` structs, and this `impl` block
904902
// requires all field types to be `FromBytes`. Thus, all
@@ -1038,10 +1036,8 @@ macro_rules! cryptocorrosion_derive_traits {
10381036
$field_ty: $crate::FromBytes,
10391037
)*
10401038
{
1041-
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
1042-
where
1043-
A: $crate::pointer::invariant::Reference
1044-
{
1039+
#[inline]
1040+
fn is_bit_valid(_c: $crate::Maybe<'_, Self>) -> bool {
10451041
// SAFETY: This macro only accepts `#[repr(C)]` unions, and this
10461042
// `impl` block requires all field types to be `FromBytes`.
10471043
// Thus, all initialized byte sequences constitutes valid

src/pointer/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ pub use {
2222
ptr::Ptr,
2323
};
2424

25+
use crate::wrappers::ReadOnly;
26+
2527
/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
2628
/// to [`TryFromBytes::is_bit_valid`].
2729
///
2830
/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
2931
pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> =
30-
Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>;
32+
Ptr<'a, ReadOnly<T>, (Aliasing, Alignment, invariant::Initialized)>;
3133

3234
/// Checks if the referent is zeroed.
3335
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
@@ -49,7 +51,7 @@ pub mod cast {
4951

5052
use crate::{
5153
layout::{SizeInfo, TrailingSliceLayout},
52-
HasField, KnownLayout, PtrInner,
54+
HasField, KnownLayout, PtrInner, REPR_C_UNION_VARIANT_ID,
5355
};
5456

5557
/// A pointer cast or projection.
@@ -313,6 +315,15 @@ pub mod cast {
313315
}
314316
}
315317

318+
// SAFETY: TODO
319+
unsafe impl<W: ?Sized, F, const FIELD_ID: i128>
320+
Cast<W, W::WrappedField> for WrappedProjection<W, F, { REPR_C_UNION_VARIANT_ID }, FIELD_ID>
321+
where
322+
W: Wrapped
323+
+ HasWrappedField<<<W as Wrapped>::Unwrapped as HasField<F, { REPR_C_UNION_VARIANT_ID }, FIELD_ID>>::Type>,
324+
W::Unwrapped: HasField<F, { REPR_C_UNION_VARIANT_ID }, FIELD_ID>,
325+
{}
326+
316327
#[allow(missing_debug_implementations, missing_copy_implementations)]
317328
pub struct TransposeProjection<W: ?Sized, V: ?Sized> {
318329
_never: core::convert::Infallible,

0 commit comments

Comments
 (0)