diff --git a/zerocopy-derive/tests/include.rs b/zerocopy-derive/tests/include.rs index c77e804952..da10b95327 100644 --- a/zerocopy-derive/tests/include.rs +++ b/zerocopy-derive/tests/include.rs @@ -124,4 +124,22 @@ pub mod util { let ptr = ptr.cast::<_, ::zerocopy::pointer::cast::CastSized, _>(); assert!(::is_bit_valid(ptr)); } + + pub fn test_is_bit_valid( + mut val: V, + is_bit_valid: bool, + ) { + use super::imp::pointer::{cast::CastSized, BecauseExclusive}; + + let candidate = ::zerocopy::Ptr::from_mut(&mut val); + let candidate = candidate.forget_aligned(); + // SAFETY: by `val: impl IntoBytes`, `val` consists entirely of + // initialized bytes. It's still unsound because this might let us + // overwrite `val` with initialized-but-invalid bytes, but we don't do + // that, so no UB is ever exercised. + let candidate = unsafe { candidate.assume_initialized() }; + let candidate = candidate.cast::(); + + super::imp::assert_eq!(T::is_bit_valid(candidate), is_bit_valid); + } } diff --git a/zerocopy-derive/tests/struct_try_from_bytes.rs b/zerocopy-derive/tests/struct_try_from_bytes.rs index eb4ab18935..fc51de3e2e 100644 --- a/zerocopy-derive/tests/struct_try_from_bytes.rs +++ b/zerocopy-derive/tests/struct_try_from_bytes.rs @@ -17,16 +17,10 @@ include!("include.rs"); #[test] fn zst() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let candidate = ::zerocopy::Ptr::from_ref(&()); - let candidate = candidate.forget_aligned(); - // SAFETY: `&()` trivially consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = <() as imp::TryFromBytes>::is_bit_valid(candidate); - imp::assert!(is_bit_valid); + crate::util::test_is_bit_valid::<(), _>((), true); } -#[derive(imp::TryFromBytes)] +#[derive(imp::TryFromBytes, imp::Immutable, imp::IntoBytes)] #[repr(C)] struct One { a: u8, @@ -36,16 +30,11 @@ util_assert_impl_all!(One: imp::TryFromBytes); #[test] fn one() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let candidate = ::zerocopy::Ptr::from_ref(&One { a: 42 }); - let candidate = candidate.forget_aligned(); - // SAFETY: `&One` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = ::is_bit_valid(candidate); - imp::assert!(is_bit_valid); + crate::util::test_is_bit_valid::(One { a: 42 }, true); + crate::util::test_is_bit_valid::(One { a: 43 }, true); } -#[derive(imp::TryFromBytes)] +#[derive(imp::TryFromBytes, imp::Immutable, imp::IntoBytes)] #[repr(C)] struct Two { a: bool, @@ -56,34 +45,9 @@ util_assert_impl_all!(Two: imp::TryFromBytes); #[test] fn two() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let candidate = ::zerocopy::Ptr::from_ref(&Two { a: false, b: () }); - let candidate = candidate.forget_aligned(); - // SAFETY: `&Two` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = ::is_bit_valid(candidate); - imp::assert!(is_bit_valid); -} - -#[test] -fn two_bad() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let mut buf = [2u8; 1]; - let candidate = ::zerocopy::Ptr::from_mut(&mut buf); - let candidate = candidate.forget_aligned(); - // SAFETY: `&Two` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - - let candidate = { - use imp::pointer::{cast::CastSized, BecauseExclusive}; - candidate.cast::<_, CastSized, (_, BecauseExclusive)>() - }; - - // SAFETY: `candidate`'s referent is as-initialized as `Two`. - let candidate = unsafe { candidate.assume_initialized() }; - - let is_bit_valid = ::is_bit_valid(candidate); - imp::assert!(!is_bit_valid); + crate::util::test_is_bit_valid::(Two { a: false, b: () }, true); + crate::util::test_is_bit_valid::(Two { a: true, b: () }, true); + crate::util::test_is_bit_valid::([2u8], false); } #[derive(imp::KnownLayout, imp::TryFromBytes)] @@ -99,11 +63,10 @@ fn un_sized() { // FIXME(#5): Use `try_transmute` in this test once it's available. let mut buf = [16u8, 12, 42]; let candidate = ::zerocopy::Ptr::from_mut(&mut buf[..]); - let candidate = candidate.forget_aligned(); // SAFETY: `&Unsized` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() }; - let candidate = { + let mut candidate = { use imp::pointer::{cast::CastUnsized, BecauseExclusive}; candidate.cast::<_, CastUnsized, (_, BecauseExclusive)>() }; @@ -145,7 +108,7 @@ where util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::TryFromBytes); -#[derive(imp::FromBytes)] +#[derive(imp::FromBytes, imp::IntoBytes)] #[repr(C)] struct MaybeFromBytes(T); @@ -155,19 +118,9 @@ fn test_maybe_from_bytes() { // trivial `is_bit_valid` impl that always returns true. This test confirms // that we *don't* spuriously do that when generic parameters are present. - let mut buf = [2u8]; - let candidate = ::zerocopy::Ptr::from_mut(&mut buf); - let candidate = candidate.bikeshed_recall_initialized_from_bytes(); - - let candidate = { - use imp::pointer::{cast::CastSized, BecauseExclusive}; - candidate.cast::, CastSized, (_, BecauseExclusive)>() - }; - - // SAFETY: `[u8]` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = as imp::TryFromBytes>::is_bit_valid(candidate); - imp::assert!(!is_bit_valid); + crate::util::test_is_bit_valid::, _>(MaybeFromBytes(false), true); + crate::util::test_is_bit_valid::, _>(MaybeFromBytes(true), true); + crate::util::test_is_bit_valid::, _>([2u8], false); } #[derive(Debug, PartialEq, Eq, imp::TryFromBytes, imp::Immutable, imp::KnownLayout)] diff --git a/zerocopy-derive/tests/union_try_from_bytes.rs b/zerocopy-derive/tests/union_try_from_bytes.rs index 382c30a972..2fa72cc2ad 100644 --- a/zerocopy-derive/tests/union_try_from_bytes.rs +++ b/zerocopy-derive/tests/union_try_from_bytes.rs @@ -24,16 +24,11 @@ util_assert_impl_all!(One: imp::TryFromBytes); #[test] fn one() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let candidate = ::zerocopy::Ptr::from_ref(&One { a: 42 }); - let candidate = candidate.forget_aligned(); - // SAFETY: `&One` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = ::is_bit_valid(candidate); - assert!(is_bit_valid); + crate::util::test_is_bit_valid::([42u8], true); + crate::util::test_is_bit_valid::([43u8], true); } -#[derive(imp::Immutable, imp::TryFromBytes)] +#[derive(imp::Immutable, imp::TryFromBytes, imp::IntoBytes)] #[repr(C)] union Two { a: bool, @@ -44,41 +39,9 @@ util_assert_impl_all!(Two: imp::TryFromBytes); #[test] fn two() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let candidate_a = ::zerocopy::Ptr::from_ref(&Two { a: false }); - let candidate_a = candidate_a.forget_aligned(); - // SAFETY: `&Two` consists entirely of initialized bytes. - let candidate_a = unsafe { candidate_a.assume_initialized() }; - let is_bit_valid = ::is_bit_valid(candidate_a); - assert!(is_bit_valid); - - let candidate_b = ::zerocopy::Ptr::from_ref(&Two { b: true }); - let candidate_b = candidate_b.forget_aligned(); - // SAFETY: `&Two` consists entirely of initialized bytes. - let candidate_b = unsafe { candidate_b.assume_initialized() }; - let is_bit_valid = ::is_bit_valid(candidate_b); - assert!(is_bit_valid); -} - -#[test] -fn two_bad() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let mut buf = [2u8]; - let candidate = ::zerocopy::Ptr::from_mut(&mut buf); - let candidate = candidate.forget_aligned(); - // SAFETY: `&[u8]` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - - let candidate = { - use imp::pointer::{cast::CastSized, BecauseExclusive}; - candidate.cast::() - }; - - // SAFETY: `candidate`'s referent is as-initialized as `Two`. - let candidate = unsafe { candidate.assume_initialized() }; - - let is_bit_valid = ::is_bit_valid(candidate); - assert!(!is_bit_valid); + crate::util::test_is_bit_valid::(Two { a: false }, true); + crate::util::test_is_bit_valid::(Two { b: true }, true); + crate::util::test_is_bit_valid::([2u8], false); } #[derive(imp::Immutable, imp::TryFromBytes)] @@ -90,23 +53,9 @@ union BoolAndZst { #[test] fn bool_and_zst() { - // FIXME(#5): Use `try_transmute` in this test once it's available. - let mut buf = [2u8]; - let candidate = ::zerocopy::Ptr::from_mut(&mut buf); - let candidate = candidate.forget_aligned(); - // SAFETY: `&[u8]` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - - let candidate = { - use imp::pointer::{cast::CastSized, BecauseExclusive}; - candidate.cast::() - }; - - // SAFETY: `candidate`'s referent is fully initialized. - let candidate = unsafe { candidate.assume_initialized() }; - - let is_bit_valid = ::is_bit_valid(candidate); - assert!(is_bit_valid); + crate::util::test_is_bit_valid::([0u8], true); + crate::util::test_is_bit_valid::([1u8], true); + crate::util::test_is_bit_valid::([2u8], true); } #[derive(imp::FromBytes)] @@ -121,19 +70,7 @@ fn test_maybe_from_bytes() { // trivial `is_bit_valid` impl that always returns true. This test confirms // that we *don't* spuriously do that when generic parameters are present. - let mut buf = [2u8]; - let candidate = ::zerocopy::Ptr::from_mut(&mut buf); - let candidate = candidate.bikeshed_recall_initialized_from_bytes(); - - let candidate = { - use imp::pointer::{cast::CastSized, BecauseExclusive}; - candidate.cast::, CastSized, (_, BecauseExclusive)>() - }; - - // SAFETY: `[u8]` consists entirely of initialized bytes. - let candidate = unsafe { candidate.assume_initialized() }; - let is_bit_valid = as imp::TryFromBytes>::is_bit_valid(candidate); - imp::assert!(!is_bit_valid); + crate::util::test_is_bit_valid::, _>([2u8], false); } #[derive(imp::Immutable, imp::TryFromBytes)]