• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Fuchsia Authors
2 //
3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6 // This file may not be copied, modified, or distributed except according to
7 // those terms.
8 
9 // See comment in `include.rs` for why we disable the prelude.
10 #![no_implicit_prelude]
11 #![allow(warnings)]
12 
13 include!("include.rs");
14 
15 // A struct is `imp::TryFromBytes` if:
16 // - any of its fields are `imp::TryFromBytes`
17 
18 #[derive(imp::Immutable, imp::TryFromBytes)]
19 union One {
20     a: u8,
21 }
22 
23 util_assert_impl_all!(One: imp::TryFromBytes);
24 
25 #[test]
one()26 fn one() {
27     // TODO(#5): Use `try_transmute` in this test once it's available.
28     let candidate = ::zerocopy::Ptr::from_ref(&One { a: 42 });
29     let candidate = candidate.forget_aligned();
30     // SAFETY: `&One` consists entirely of initialized bytes.
31     let candidate = unsafe { candidate.assume_initialized() };
32     let is_bit_valid = <One as imp::TryFromBytes>::is_bit_valid(candidate);
33     assert!(is_bit_valid);
34 }
35 
36 #[derive(imp::Immutable, imp::TryFromBytes)]
37 #[repr(C)]
38 union Two {
39     a: bool,
40     b: bool,
41 }
42 
43 util_assert_impl_all!(Two: imp::TryFromBytes);
44 
45 #[test]
two()46 fn two() {
47     // TODO(#5): Use `try_transmute` in this test once it's available.
48     let candidate_a = ::zerocopy::Ptr::from_ref(&Two { a: false });
49     let candidate_a = candidate_a.forget_aligned();
50     // SAFETY: `&Two` consists entirely of initialized bytes.
51     let candidate_a = unsafe { candidate_a.assume_initialized() };
52     let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate_a);
53     assert!(is_bit_valid);
54 
55     let candidate_b = ::zerocopy::Ptr::from_ref(&Two { b: true });
56     let candidate_b = candidate_b.forget_aligned();
57     // SAFETY: `&Two` consists entirely of initialized bytes.
58     let candidate_b = unsafe { candidate_b.assume_initialized() };
59     let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate_b);
60     assert!(is_bit_valid);
61 }
62 
63 #[test]
two_bad()64 fn two_bad() {
65     // TODO(#5): Use `try_transmute` in this test once it's available.
66     let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
67     let candidate = candidate.forget_aligned();
68     // SAFETY: `&[u8]` consists entirely of initialized bytes.
69     let candidate = unsafe { candidate.assume_initialized() };
70 
71     // SAFETY:
72     // - The cast preserves address and size. As a result, the cast will address
73     //   the same bytes as `c`.
74     // - The cast preserves provenance.
75     // - Neither the input nor output types contain any `UnsafeCell`s.
76     let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) };
77 
78     // SAFETY: `candidate`'s referent is as-initialized as `Two`.
79     let candidate = unsafe { candidate.assume_initialized() };
80 
81     let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate);
82     assert!(!is_bit_valid);
83 }
84 
85 #[derive(imp::Immutable, imp::TryFromBytes)]
86 #[repr(C)]
87 union BoolAndZst {
88     a: bool,
89     b: (),
90 }
91 
92 #[test]
bool_and_zst()93 fn bool_and_zst() {
94     // TODO(#5): Use `try_transmute` in this test once it's available.
95     let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
96     let candidate = candidate.forget_aligned();
97     // SAFETY: `&[u8]` consists entirely of initialized bytes.
98     let candidate = unsafe { candidate.assume_initialized() };
99 
100     // SAFETY:
101     // - The cast preserves address and size. As a result, the cast will address
102     //   the same bytes as `c`.
103     // - The cast preserves provenance.
104     // - Neither the input nor output types contain any `UnsafeCell`s.
105     let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut BoolAndZst) };
106 
107     // SAFETY: `candidate`'s referent is fully initialized.
108     let candidate = unsafe { candidate.assume_initialized() };
109 
110     let is_bit_valid = <BoolAndZst as imp::TryFromBytes>::is_bit_valid(candidate);
111     assert!(is_bit_valid);
112 }
113 
114 #[derive(imp::FromBytes)]
115 #[repr(C)]
116 union MaybeFromBytes<T: imp::Copy> {
117     t: T,
118 }
119 
120 #[test]
test_maybe_from_bytes()121 fn test_maybe_from_bytes() {
122     // When deriving `FromBytes` on a type with no generic parameters, we emit a
123     // trivial `is_bit_valid` impl that always returns true. This test confirms
124     // that we *don't* spuriously do that when generic parameters are present.
125 
126     let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
127     let candidate = candidate.bikeshed_recall_initialized_from_bytes();
128 
129     // SAFETY:
130     // - The cast preserves address and size. As a result, the cast will address
131     //   the same bytes as `c`.
132     // - The cast preserves provenance.
133     // - Neither the input nor output types contain any `UnsafeCell`s.
134     let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes<bool>) };
135 
136     // SAFETY: `[u8]` consists entirely of initialized bytes.
137     let candidate = unsafe { candidate.assume_initialized() };
138     let is_bit_valid = <MaybeFromBytes<bool> as imp::TryFromBytes>::is_bit_valid(candidate);
139     imp::assert!(!is_bit_valid);
140 }
141 
142 #[derive(imp::Immutable, imp::TryFromBytes)]
143 #[repr(C)]
144 union TypeParams<'a, T: imp::Copy, I: imp::Iterator>
145 where
146     I::Item: imp::Copy,
147 {
148     a: I::Item,
149     b: u8,
150     c: imp::PhantomData<&'a [u8]>,
151     d: imp::PhantomData<&'static str>,
152     e: imp::PhantomData<imp::String>,
153     f: T,
154 }
155 
156 util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::TryFromBytes);
157 util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::TryFromBytes);
158 util_assert_impl_all!(TypeParams<'static, [util::AU16; 2], imp::IntoIter<()>>: imp::TryFromBytes);
159 
160 // Deriving `imp::TryFromBytes` should work if the union has bounded parameters.
161 
162 #[derive(imp::Immutable, imp::TryFromBytes)]
163 #[repr(C)]
164 union WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::TryFromBytes, const N: usize>
165 where
166     'a: 'b,
167     'b: 'a,
168     T: 'a + 'b + imp::TryFromBytes + imp::Copy,
169 {
170     a: imp::PhantomData<&'a &'b ()>,
171     b: T,
172 }
173 
174 util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::TryFromBytes);
175 
176 #[derive(Clone, Copy, imp::TryFromBytes, imp::Immutable)]
177 struct A;
178 
179 #[derive(imp::TryFromBytes)]
180 union B {
181     a: A,
182 }
183