@@ -1801,6 +1801,237 @@ safety_comment! {
18011801 assert_unaligned!( mem:: MaybeUninit <( ) >, MaybeUninit <u8 >) ;
18021802}
18031803
1804+ /// A value which might or might not constitute a valid instance of `T`.
1805+ ///
1806+ /// `MaybeValid<T>` has the same layout (size and alignment) and field offsets
1807+ /// as `T`. Unlike `T`, it may contain any bit pattern, except that
1808+ /// uninitialized bytes may only appear in `MaybeValid<T>` at byte offsets where
1809+ /// they may appear in `T`. This is a dynamic property: if, at a particular byte
1810+ /// offset, a valid enum discriminant is set, the subsequent bytes may only have
1811+ /// uninitialized bytes as specified by the corresponding enum variant.
1812+ ///
1813+ /// Formally, given `m: MaybeValid<T>` and a byte offset, `b` in the range `[0,
1814+ /// size_of_val(m))`:
1815+ /// - If, in all valid instances `t: T`, the byte at offset `b` in `t` is
1816+ /// initialized, then the byte at offset `b` within `m` is guaranteed to be
1817+ /// initialized.
1818+ /// - Let `c` be the contents of the byte range `[0, b)` in `m`. Let `TT` be the
1819+ /// subset of valid instances of `T` which contain `c` in the offset range
1820+ /// `[0, b)`. If, for all instances of `t: T` in `TT`, the byte at offset `b`
1821+ /// in `t` is initialized, then the byte at offset `b` in `m` is guaranteed to
1822+ /// be initialized.
1823+ ///
1824+ /// Pragmatically, this means that if `m` is guaranteed to contain an enum
1825+ /// type at a particular offset, and the enum discriminant stored in `m`
1826+ /// corresponds to a valid variant of that enum type, then it is guaranteed
1827+ /// that the appropriate bytes of `m` are initialized as defined by that
1828+ /// variant's bit validity (although note that the variant may contain another
1829+ /// enum type, in which case the same rules apply depending on the state of
1830+ /// its discriminant, and so on recursively).
1831+ ///
1832+ /// # Safety
1833+ ///
1834+ /// Unsafe code may assume that an instance of `MaybeValid` satisfies the
1835+ /// constraints described above. Unsafe code may produce a `MaybeValid` or
1836+ /// modify the bytes of an existing `MaybeValid` so long as these constraints
1837+ /// are upheld. It is unsound to produce a `MaybeValid` which fails to uphold
1838+ /// these constraints.
1839+ #[ repr( transparent) ]
1840+ pub struct MaybeValid < T : AsMaybeUninit + ?Sized > {
1841+ inner : MaybeUninit < T > ,
1842+ }
1843+
1844+ safety_comment ! {
1845+ /// SAFETY:
1846+ /// - `AsBytes`: `MaybeValid` requires that, if a byte in `T` is always
1847+ /// initialized, the equivalent byte in `MaybeValid<T>` must be
1848+ /// initialized. `T: AsBytes` implies that all bytes in `T` must always be
1849+ /// initialized, and so all bytes in `MaybeValid<T>` must always be
1850+ /// initialized, and so `MaybeValid<T>` satisfies `AsBytes`. `T: AsBytes`
1851+ /// implies that `[T]: AsBytes`, so this holds is a sufficient bound for
1852+ /// `MaybeValid<[T]>` too.
1853+ /// - `Unaligned`: `MaybeValid<T>` and `MaybeValid<[T]>` have the same
1854+ /// alignment as `T`.
1855+ ///
1856+ /// TODO(#5): Implement `FromZeroes` and `FromBytes` for `MaybeValid<T>` and
1857+ /// `MaybeValid<[T]>`.
1858+ unsafe_impl!( T : AsBytes => AsBytes for MaybeValid <T >) ;
1859+ unsafe_impl!( T : AsBytes => AsBytes for MaybeValid <[ T ] >) ;
1860+ unsafe_impl!( T : Unaligned => Unaligned for MaybeValid <T >) ;
1861+ unsafe_impl!( T : Unaligned => Unaligned for MaybeValid <[ T ] >) ;
1862+ }
1863+
1864+ unsafe_impl_known_layout ! ( T => #[ repr( [ T ] ) ] MaybeValid <[ T ] >) ;
1865+
1866+ // SAFETY: See safety comment on `MaybeUninit`.
1867+ unsafe impl < T > AsMaybeUninit for MaybeValid < [ T ] > {
1868+ // SAFETY:
1869+ // - `MaybeUninit` has no bit validity requirements and `[U]` has the same
1870+ // bit validity requirements as `U`, so `[MaybeUninit<T>]` has no bit
1871+ // validity requirements. Thus, it is sound to write uninitialized bytes
1872+ // at every offset.
1873+ // - `MaybeValid<U>` is `repr(transparent)`, and thus has the same layout
1874+ // and field offsets as its contained field of type `U::MaybeUninit`. In
1875+ // this case, `U = [T]`, and so `U::MaybeUninit = [MaybeUninit<T>]`. Thus,
1876+ // `MaybeValid<[T]>` has the same layout and field offsets as
1877+ // `[MaybeUninit<T>]`, which is what we set `MaybeUninit` to here. Thus,
1878+ // they trivially have the same alignment.
1879+ // - By the same token, their raw pointer types are trivially `as` castable
1880+ // and preserve size.
1881+ // - By the same token, `[MaybeUninit<T>]` contains `UnsafeCell`s at the
1882+ // same byte ranges as `MaybeValid<[T]>` does.
1883+ type MaybeUninit = [ MaybeUninit < T > ] ;
1884+
1885+ // SAFETY: `as` preserves pointer address and provenance.
1886+ #[ allow( clippy:: as_conversions) ]
1887+ fn raw_from_maybe_uninit ( maybe_uninit : * const [ MaybeUninit < T > ] ) -> * const MaybeValid < [ T ] > {
1888+ maybe_uninit as * const MaybeValid < [ T ] >
1889+ }
1890+
1891+ // SAFETY: `as` preserves pointer address and provenance.
1892+ #[ allow( clippy:: as_conversions) ]
1893+ fn raw_mut_from_maybe_uninit ( maybe_uninit : * mut [ MaybeUninit < T > ] ) -> * mut MaybeValid < [ T ] > {
1894+ maybe_uninit as * mut MaybeValid < [ T ] >
1895+ }
1896+
1897+ // SAFETY: `as` preserves pointer address and provenance.
1898+ #[ allow( clippy:: as_conversions) ]
1899+ fn raw_maybe_uninit_from ( s : * const MaybeValid < [ T ] > ) -> * const [ MaybeUninit < T > ] {
1900+ s as * const [ MaybeUninit < T > ]
1901+ }
1902+ }
1903+
1904+ impl < T > Default for MaybeValid < T > {
1905+ fn default ( ) -> MaybeValid < T > {
1906+ // SAFETY: All of the bytes of `inner` are initialized to 0, and so the
1907+ // safety invariant on `MaybeValid` is upheld.
1908+ MaybeValid { inner : MaybeUninit :: zeroed ( ) }
1909+ }
1910+ }
1911+
1912+ impl < T : AsMaybeUninit + ?Sized > MaybeValid < T > {
1913+ /// Converts this `&MaybeValid<T>` to a `&T`.
1914+ ///
1915+ /// # Safety
1916+ ///
1917+ /// `self` must contain a valid `T`.
1918+ pub unsafe fn assume_valid_ref ( & self ) -> & T {
1919+ // SAFETY: The caller has promised that `self` contains a valid `T`.
1920+ // Since `Self` is `repr(transparent)`, it has the same layout as
1921+ // `MaybeUninit<T>`, which in turn is guaranteed to have the same layout
1922+ // as `T`. Thus, it is sound to treat `self.inner` as containing a valid
1923+ // `T`.
1924+ unsafe { self . inner . assume_init_ref ( ) }
1925+ }
1926+
1927+ /// Converts this `&mut MaybeValid<T>` to a `&mut T`.
1928+ ///
1929+ /// # Safety
1930+ ///
1931+ /// `self` must contain a valid `T`.
1932+ pub unsafe fn assume_valid_mut ( & mut self ) -> & mut T {
1933+ // SAFETY: The caller has promised that `self` contains a valid `T`.
1934+ // Since `Self` is `repr(transparent)`, it has the same layout as
1935+ // `MaybeUninit<T>`, which in turn is guaranteed to have the same layout
1936+ // as `T`. Thus, it is sound to treat `self.inner` as containing a valid
1937+ // `T`.
1938+ unsafe { self . inner . assume_init_mut ( ) }
1939+ }
1940+
1941+ /// Gets a view of this `&T` as a `&MaybeValid<T>`.
1942+ ///
1943+ /// There is no mutable equivalent to this function, as producing a `&mut
1944+ /// MaybeValid<T>` from a `&mut T` would allow safe code to write invalid
1945+ /// values which would be accessible through `&mut T`.
1946+ pub fn from_ref ( r : & T ) -> & MaybeValid < T > {
1947+ let m: * const MaybeUninit < T > = MaybeUninit :: from_ref ( r) ;
1948+ #[ allow( clippy:: as_conversions) ]
1949+ let ptr = m as * const MaybeValid < T > ;
1950+ // SAFETY: Since `Self` is `repr(transparent)`, it has the same layout
1951+ // as `MaybeUninit<T>`, so the size and alignment here are valid.
1952+ //
1953+ // `MaybeValid<T>`'s bit validity constraints are weaker than those of
1954+ // `T`, so this is guaranteed not to produce an invalid `MaybeValid<T>`.
1955+ // If it were possible to write a different value for `MaybeValid<T>`
1956+ // through the returned reference, it could result in an invalid value
1957+ // being exposed via the `&T`. Luckily, the only way for mutation to
1958+ // happen is if `T` contains an `UnsafeCell` and the caller uses it to
1959+ // perform interior mutation. Importantly, `T` containing an
1960+ // `UnsafeCell` does not permit interior mutation through
1961+ // `MaybeValid<T>`, so it doesn't permit writing uninitialized or
1962+ // otherwise invalid values which would be visible through the original
1963+ // `&T`.
1964+ unsafe { & * ptr }
1965+ }
1966+ }
1967+
1968+ impl < T > MaybeValid < T > {
1969+ /// Converts this `MaybeValid<T>` to a `T`.
1970+ ///
1971+ /// # Safety
1972+ ///
1973+ /// `self` must contain a valid `T`.
1974+ pub const unsafe fn assume_valid ( self ) -> T {
1975+ // SAFETY: The caller has promised that `self` contains a valid `T`.
1976+ // Since `Self` is `repr(transparent)`, it has the same layout as
1977+ // `MaybeUninit<T>`, which in turn is guaranteed to have the same layout
1978+ // as `T`. Thus, it is sound to treat `self.inner` as containing a valid
1979+ // `T`.
1980+ unsafe { self . inner . assume_init ( ) }
1981+ }
1982+ }
1983+
1984+ impl < T > MaybeValid < [ T ] > {
1985+ /// Converts a `MaybeValid<[T]>` to a `[MaybeValid<T>]`.
1986+ ///
1987+ /// `MaybeValid<T>` has the same layout as `T`, so these layouts are
1988+ /// equivalent.
1989+ pub const fn as_slice_of_maybe_valids ( & self ) -> & [ MaybeValid < T > ] {
1990+ let inner: & [ <T as AsMaybeUninit >:: MaybeUninit ] = & self . inner . inner ;
1991+ let inner_ptr: * const [ <T as AsMaybeUninit >:: MaybeUninit ] = inner;
1992+ // Note: this Clippy warning is only emitted on our MSRV (1.61), but not
1993+ // on later versions of Clippy. Thus, we consider it spurious.
1994+ #[ allow( clippy:: as_conversions) ]
1995+ let ret_ptr = inner_ptr as * const [ MaybeValid < T > ] ;
1996+ // SAFETY: Since `inner` is a `&[MaybeUninit<T>]`, and `MaybeValid<T>`
1997+ // is a `repr(transparent)` struct around `MaybeUninit<T>`, `inner` has
1998+ // the same layout as `&[MaybeValid<T>]`.
1999+ unsafe { & * ret_ptr }
2000+ }
2001+ }
2002+
2003+ impl < const N : usize , T > MaybeValid < [ T ; N ] > {
2004+ /// Converts a `MaybeValid<[T; N]>` to a `MaybeValid<[T]>`.
2005+ // TODO(#64): Make this `const` once our MSRV is >= 1.64.0 (when
2006+ // `slice_from_raw_parts` was stabilized as `const`).
2007+ pub fn as_slice ( & self ) -> & MaybeValid < [ T ] > {
2008+ let base: * const MaybeValid < [ T ; N ] > = self ;
2009+ let slice_of_t: * const [ T ] = ptr:: slice_from_raw_parts ( base. cast :: < T > ( ) , N ) ;
2010+ // Note: this Clippy warning is only emitted on our MSRV (1.61), but not
2011+ // on later versions of Clippy. Thus, we consider it spurious.
2012+ #[ allow( clippy:: as_conversions) ]
2013+ let mv_of_slice = slice_of_t as * const MaybeValid < [ T ] > ;
2014+ // SAFETY: `MaybeValid<T>` is a `repr(transparent)` wrapper around
2015+ // `MaybeUninit<T>`, which in turn has the same layout as `T`. Thus, the
2016+ // trailing slices of `[T]` and of `MaybeValid<[T]>` both have element
2017+ // type `T`. Since the number of elements is preserved during an `as`
2018+ // cast of slice/DST pointers, the resulting `*const MaybeValid<[T]>`
2019+ // has the same number of elements - and thus the same length - as the
2020+ // original `*const [T]`.
2021+ //
2022+ // Thanks to their layouts, `MaybeValid<[T; N]>` and `MaybeValid<[T]>`
2023+ // have the same alignment, so `mv_of_slice` is guaranteed to be
2024+ // aligned.
2025+ unsafe { & * mv_of_slice }
2026+ }
2027+ }
2028+
2029+ impl < T > Debug for MaybeValid < T > {
2030+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
2031+ f. pad ( core:: any:: type_name :: < Self > ( ) )
2032+ }
2033+ }
2034+
18042035/// A type with no alignment requirement.
18052036///
18062037/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign<T>`
@@ -3841,6 +4072,91 @@ mod tests {
38414072 assert_eq ! ( unsafe { m. assume_init_ref( ) } , & Cell :: new( 2 ) ) ;
38424073 }
38434074
4075+ #[ test]
4076+ fn test_maybe_valid ( ) {
4077+ let m = MaybeValid :: < usize > :: default ( ) ;
4078+ // SAFETY: all bit patterns are valid `usize`s, and `m` is initialized.
4079+ let u = unsafe { m. assume_valid ( ) } ;
4080+ // This ensures that Miri can see whether `u` (and thus `m`) has been
4081+ // properly initialized.
4082+ assert_eq ! ( u, u) ;
4083+
4084+ fn bytes_to_maybe_valid ( bytes : & mut [ u8 ] ) -> & mut MaybeValid < [ u8 ] > {
4085+ // SAFETY: `MaybeValid<[u8]>` has the same layout as `[u8]`, and
4086+ // `bytes` is initialized.
4087+ unsafe {
4088+ #[ allow( clippy:: as_conversions) ]
4089+ let m = & mut * ( bytes as * mut [ u8 ] as * mut MaybeValid < [ u8 ] > ) ;
4090+ m
4091+ }
4092+ }
4093+
4094+ let mut bytes = [ 0u8 , 1 , 2 ] ;
4095+ let m = bytes_to_maybe_valid ( & mut bytes[ ..] ) ;
4096+
4097+ // SAFETY: `m` was created from a valid `[u8]`.
4098+ let r = unsafe { m. assume_valid_ref ( ) } ;
4099+ assert_eq ! ( r. len( ) , 3 ) ;
4100+ assert_eq ! ( r, [ 0 , 1 , 2 ] ) ;
4101+
4102+ // SAFETY: `m` was created from a valid `[u8]`.
4103+ let r = unsafe { m. assume_valid_mut ( ) } ;
4104+ assert_eq ! ( r. len( ) , 3 ) ;
4105+ assert_eq ! ( r, [ 0 , 1 , 2 ] ) ;
4106+
4107+ r[ 0 ] = 1 ;
4108+ assert_eq ! ( bytes, [ 1 , 1 , 2 ] ) ;
4109+
4110+ let mut bytes = [ 0u8 , 1 , 2 ] ;
4111+ let m = bytes_to_maybe_valid ( & mut bytes[ ..] ) ;
4112+ let slc = m. as_slice_of_maybe_valids ( ) ;
4113+ assert_eq ! ( slc. len( ) , 3 ) ;
4114+ for i in 0u8 ..3 {
4115+ // SAFETY: `m` was created from a valid `[u8]`.
4116+ let u = unsafe { slc[ usize:: from ( i) ] . assume_valid_ref ( ) } ;
4117+ assert_eq ! ( u, & i) ;
4118+ }
4119+ }
4120+
4121+ #[ test]
4122+ fn test_maybe_valid_as_slice ( ) {
4123+ let mut m = MaybeValid :: < [ u8 ; 3 ] > :: default ( ) ;
4124+ // SAFETY: all bit patterns are valid `[u8; 3]`s, and `m` is
4125+ // initialized.
4126+ unsafe { * m. assume_valid_mut ( ) = [ 0 , 1 , 2 ] } ;
4127+
4128+ let slc = m. as_slice ( ) . as_slice_of_maybe_valids ( ) ;
4129+ assert_eq ! ( slc. len( ) , 3 ) ;
4130+
4131+ for i in 0u8 ..3 {
4132+ // SAFETY: `m` was initialized as a valid `[u8; 3]`.
4133+ let u = unsafe { slc[ usize:: from ( i) ] . assume_valid_ref ( ) } ;
4134+ assert_eq ! ( u, & i) ;
4135+ }
4136+ }
4137+
4138+ #[ test]
4139+ fn test_maybe_valid_from_ref ( ) {
4140+ use core:: cell:: Cell ;
4141+
4142+ let u = 1usize ;
4143+ let m = MaybeValid :: from_ref ( & u) ;
4144+ // SAFETY: `m` was constructed from a valid `&usize`.
4145+ assert_eq ! ( unsafe { m. assume_valid_ref( ) } , & 1usize ) ;
4146+
4147+ // Test that interior mutability doesn't affect correctness or
4148+ // soundness.
4149+
4150+ let c = Cell :: new ( 1usize ) ;
4151+ let m = MaybeValid :: from_ref ( & c) ;
4152+ // SAFETY: `m` was constructed from a valid `&usize`.
4153+ assert_eq ! ( unsafe { m. assume_valid_ref( ) } , & Cell :: new( 1 ) ) ;
4154+
4155+ c. set ( 2 ) ;
4156+ // SAFETY: `m` was constructed from a valid `&usize`.
4157+ assert_eq ! ( unsafe { m. assume_valid_ref( ) } , & Cell :: new( 2 ) ) ;
4158+ }
4159+
38444160 #[ test]
38454161 fn test_unalign ( ) {
38464162 // Test methods that don't depend on alignment.
@@ -4776,6 +5092,12 @@ mod tests {
47765092 assert_impls ! ( MaybeUninit <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
47775093 assert_impls ! ( MaybeUninit <MaybeUninit <NotZerocopy >>: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
47785094
5095+ assert_impls ! ( MaybeValid <u8 >: Unaligned , AsBytes , !FromZeroes , !FromBytes ) ;
5096+ assert_impls ! ( MaybeValid <MaybeValid <u8 >>: Unaligned , AsBytes , !FromZeroes , !FromBytes ) ;
5097+ assert_impls ! ( MaybeValid <[ u8 ] >: Unaligned , AsBytes , !FromZeroes , !FromBytes ) ;
5098+ assert_impls ! ( MaybeValid <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
5099+ assert_impls ! ( MaybeValid <MaybeValid <NotZerocopy >>: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
5100+
47795101 assert_impls ! ( Wrapping <u8 >: FromZeroes , FromBytes , AsBytes , Unaligned ) ;
47805102 assert_impls ! ( Wrapping <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
47815103
0 commit comments