@@ -13,6 +13,8 @@ use safety::{ensures, requires};
1313
1414#[ cfg( kani) ]
1515use crate :: kani;
16+ #[ cfg( kani) ]
17+ use crate :: ub_checks;
1618
1719/// `*mut T` but non-zero and [covariant].
1820///
@@ -568,7 +570,7 @@ impl<T: ?Sized> NonNull<T> {
568570 #[ must_use = "returns a new pointer rather than modifying its argument" ]
569571 #[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
570572 #[ rustc_const_stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
571- #[ requires( count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( )
573+ #[ requires( count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( )
572574 && count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize
573575 && ( self . pointer as isize ) . checked_add( count as isize * core:: mem:: size_of:: <T >( ) as isize ) . is_some( ) // check wrapping add
574576 && kani:: mem:: same_allocation( self . pointer, self . pointer. wrapping_offset( count as isize ) ) ) ]
@@ -910,6 +912,7 @@ impl<T: ?Sized> NonNull<T> {
910912 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
911913 #[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
912914 #[ rustc_const_stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
915+ #[ requires( ub_checks:: can_dereference( self . pointer) ) ]
913916 pub const unsafe fn read ( self ) -> T
914917 where
915918 T : Sized ,
@@ -931,6 +934,7 @@ impl<T: ?Sized> NonNull<T> {
931934 #[ inline]
932935 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
933936 #[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
937+ #[ requires( ub_checks:: can_dereference( self . pointer) ) ]
934938 pub unsafe fn read_volatile ( self ) -> T
935939 where
936940 T : Sized ,
@@ -951,6 +955,7 @@ impl<T: ?Sized> NonNull<T> {
951955 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
952956 #[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
953957 #[ rustc_const_stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
958+ #[ requires( ub_checks:: can_read_unaligned( self . pointer) ) ]
954959 pub const unsafe fn read_unaligned ( self ) -> T
955960 where
956961 T : Sized ,
@@ -1219,9 +1224,9 @@ impl<T: ?Sized> NonNull<T> {
12191224 let stride = crate :: mem:: size_of:: <T >( ) ;
12201225 // ZSTs
12211226 if stride == 0 {
1222- if self . pointer. addr( ) % align == 0 {
1227+ if self . pointer. addr( ) % align == 0 {
12231228 return * result == 0 ;
1224- } else {
1229+ } else {
12251230 return * result == usize :: MAX ;
12261231 }
12271232 }
@@ -1233,8 +1238,8 @@ impl<T: ?Sized> NonNull<T> {
12331238 // requires computing gcd(a, stride), which is too expensive without
12341239 // quantifiers (https://model-checking.github.io/kani/rfc/rfcs/0010-quantifiers.html).
12351240 // This should be updated once quantifiers are available.
1236- if ( align % stride != 0 && * result == usize :: MAX ) {
1237- return true ;
1241+ if ( align % stride != 0 && * result == usize :: MAX ) {
1242+ return true ;
12381243 }
12391244 // If we reach this case, either:
12401245 // - align % stride == 0 and self.pointer.addr() % stride == 0, so it is definitely possible to align the pointer
@@ -1867,6 +1872,79 @@ mod verify {
18671872 let _ = NonNull :: new ( maybe_null_ptr) ;
18681873 }
18691874
1875+ // pub const unsafe fn read(self) -> T where T: Sized
1876+ #[ kani:: proof_for_contract( NonNull :: read) ]
1877+ pub fn non_null_check_read ( ) {
1878+ let ptr_u8: * mut u8 = & mut kani:: any ( ) ;
1879+ let nonnull_ptr_u8 = NonNull :: new ( ptr_u8) . unwrap ( ) ;
1880+ unsafe {
1881+ let result = nonnull_ptr_u8. read ( ) ;
1882+ kani:: assert ( * ptr_u8 == result, "read returns the correct value" ) ;
1883+ }
1884+
1885+ // array example
1886+ const ARR_LEN : usize = 10000 ;
1887+ let mut generator = PointerGenerator :: < ARR_LEN > :: new ( ) ;
1888+ let raw_ptr: * mut i8 = generator. any_in_bounds ( ) . ptr ;
1889+ let nonnull_ptr = unsafe { NonNull :: new ( raw_ptr) . unwrap ( ) } ;
1890+ unsafe {
1891+ let result = nonnull_ptr. read ( ) ;
1892+ kani:: assert ( * nonnull_ptr. as_ptr ( ) == result, "read returns the correct value" ) ;
1893+ }
1894+ }
1895+
1896+ // pub unsafe fn read_volatile(self) -> T where T: Sized
1897+ #[ kani:: proof_for_contract( NonNull :: read_volatile) ]
1898+ pub fn non_null_check_read_volatile ( ) {
1899+ let ptr_u8: * mut u8 = & mut kani:: any ( ) ;
1900+ let nonnull_ptr_u8 = NonNull :: new ( ptr_u8) . unwrap ( ) ;
1901+ unsafe {
1902+ let result = nonnull_ptr_u8. read_volatile ( ) ;
1903+ kani:: assert ( * ptr_u8 == result, "read returns the correct value" ) ;
1904+ }
1905+
1906+ // array example
1907+ const ARR_LEN : usize = 10000 ;
1908+ let mut generator = PointerGenerator :: < ARR_LEN > :: new ( ) ;
1909+ let raw_ptr: * mut i8 = generator. any_in_bounds ( ) . ptr ;
1910+ let nonnull_ptr = unsafe { NonNull :: new ( raw_ptr) . unwrap ( ) } ;
1911+ unsafe {
1912+ let result = nonnull_ptr. read_volatile ( ) ;
1913+ kani:: assert ( * nonnull_ptr. as_ptr ( ) == result, "read returns the correct value" ) ;
1914+ }
1915+ }
1916+
1917+ #[ repr( packed, C ) ]
1918+ struct Packed {
1919+ _padding : u8 ,
1920+ unaligned : u32 ,
1921+ }
1922+
1923+ // pub const unsafe fn read_unaligned(self) -> T where T: Sized
1924+ #[ kani:: proof_for_contract( NonNull :: read_unaligned) ]
1925+ pub fn non_null_check_read_unaligned ( ) {
1926+ // unaligned pointer
1927+ let mut generator = PointerGenerator :: < 10000 > :: new ( ) ;
1928+ let unaligned_ptr: * mut u8 = generator. any_in_bounds ( ) . ptr ;
1929+ let unaligned_nonnull_ptr = NonNull :: new ( unaligned_ptr) . unwrap ( ) ;
1930+ unsafe {
1931+ let result = unaligned_nonnull_ptr. read_unaligned ( ) ;
1932+ kani:: assert ( * unaligned_nonnull_ptr. as_ptr ( ) == result, "read returns the correct value" ) ;
1933+ }
1934+
1935+ // read an unaligned value from a packed struct
1936+ let unaligned_value: u32 = kani:: any ( ) ;
1937+ let packed = Packed {
1938+ _padding : kani:: any :: < u8 > ( ) ,
1939+ unaligned : unaligned_value,
1940+ } ;
1941+
1942+ let unaligned_ptr = ptr:: addr_of!( packed. unaligned) ;
1943+ let nonnull_packed_ptr = NonNull :: new ( unaligned_ptr as * mut u32 ) . unwrap ( ) ;
1944+ let v = unsafe { nonnull_packed_ptr. read_unaligned ( ) } ;
1945+ assert_eq ! ( v, unaligned_value) ;
1946+ }
1947+
18701948 // pub const unsafe fn add(self, count: usize) -> Self
18711949 #[ kani:: proof_for_contract( NonNull :: add) ]
18721950 pub fn non_null_check_add ( ) {
@@ -1875,16 +1953,16 @@ mod verify {
18751953 let raw_ptr: * mut i8 = generator. any_in_bounds ( ) . ptr ;
18761954 let ptr = unsafe { NonNull :: new ( raw_ptr) . unwrap ( ) } ;
18771955 // Create a non-deterministic count value
1878- let count: usize = kani:: any ( ) ;
1879-
1956+ let count: usize = kani:: any ( ) ;
1957+
18801958 unsafe {
18811959 let result = ptr. add ( count) ;
18821960 }
18831961 }
18841962
18851963 // pub fn addr(self) -> NonZero<usize>
18861964 #[ kani:: proof_for_contract( NonNull :: addr) ]
1887- pub fn non_null_check_addr ( ) {
1965+ pub fn non_null_check_addr ( ) {
18881966 // Create NonNull pointer & get pointer address
18891967 let x = kani:: any :: < usize > ( ) as * mut i32 ;
18901968 let Some ( nonnull_xptr) = NonNull :: new ( x) else { return ; } ;
@@ -1897,7 +1975,7 @@ mod verify {
18971975 // Create NonNull pointer
18981976 let x = kani:: any :: < usize > ( ) as * mut i32 ;
18991977 let Some ( nonnull_xptr) = NonNull :: new ( x) else { return ; } ;
1900-
1978+
19011979 // Call align_offset with valid align value
19021980 let align: usize = kani:: any ( ) ;
19031981 kani:: assume ( align. is_power_of_two ( ) ) ;
@@ -1914,7 +1992,7 @@ mod verify {
19141992
19151993 // Generate align value that is not necessarily a power of two
19161994 let invalid_align: usize = kani:: any ( ) ;
1917-
1995+
19181996 // Trigger panic
19191997 let offset = nonnull_xptr. align_offset ( invalid_align) ;
19201998 }
0 commit comments