@@ -13,6 +13,8 @@ use safety::{ensures, requires};
13
13
14
14
#[ cfg( kani) ]
15
15
use crate :: kani;
16
+ #[ cfg( kani) ]
17
+ use crate :: ub_checks;
16
18
17
19
/// `*mut T` but non-zero and [covariant].
18
20
///
@@ -568,7 +570,7 @@ impl<T: ?Sized> NonNull<T> {
568
570
#[ must_use = "returns a new pointer rather than modifying its argument" ]
569
571
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
570
572
#[ 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( )
572
574
&& count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize
573
575
&& ( self . pointer as isize ) . checked_add( count as isize * core:: mem:: size_of:: <T >( ) as isize ) . is_some( ) // check wrapping add
574
576
&& kani:: mem:: same_allocation( self . pointer, self . pointer. wrapping_offset( count as isize ) ) ) ]
@@ -910,6 +912,7 @@ impl<T: ?Sized> NonNull<T> {
910
912
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
911
913
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
912
914
#[ rustc_const_stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
915
+ #[ requires( ub_checks:: can_dereference( self . pointer) ) ]
913
916
pub const unsafe fn read ( self ) -> T
914
917
where
915
918
T : Sized ,
@@ -931,6 +934,7 @@ impl<T: ?Sized> NonNull<T> {
931
934
#[ inline]
932
935
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
933
936
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
937
+ #[ requires( ub_checks:: can_dereference( self . pointer) ) ]
934
938
pub unsafe fn read_volatile ( self ) -> T
935
939
where
936
940
T : Sized ,
@@ -951,6 +955,7 @@ impl<T: ?Sized> NonNull<T> {
951
955
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
952
956
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
953
957
#[ rustc_const_stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
958
+ #[ requires( ub_checks:: can_read_unaligned( self . pointer) ) ]
954
959
pub const unsafe fn read_unaligned ( self ) -> T
955
960
where
956
961
T : Sized ,
@@ -1219,9 +1224,9 @@ impl<T: ?Sized> NonNull<T> {
1219
1224
let stride = crate :: mem:: size_of:: <T >( ) ;
1220
1225
// ZSTs
1221
1226
if stride == 0 {
1222
- if self . pointer. addr( ) % align == 0 {
1227
+ if self . pointer. addr( ) % align == 0 {
1223
1228
return * result == 0 ;
1224
- } else {
1229
+ } else {
1225
1230
return * result == usize :: MAX ;
1226
1231
}
1227
1232
}
@@ -1233,8 +1238,8 @@ impl<T: ?Sized> NonNull<T> {
1233
1238
// requires computing gcd(a, stride), which is too expensive without
1234
1239
// quantifiers (https://model-checking.github.io/kani/rfc/rfcs/0010-quantifiers.html).
1235
1240
// 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 ;
1238
1243
}
1239
1244
// If we reach this case, either:
1240
1245
// - align % stride == 0 and self.pointer.addr() % stride == 0, so it is definitely possible to align the pointer
@@ -1867,6 +1872,79 @@ mod verify {
1867
1872
let _ = NonNull :: new ( maybe_null_ptr) ;
1868
1873
}
1869
1874
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
+
1870
1948
// pub const unsafe fn add(self, count: usize) -> Self
1871
1949
#[ kani:: proof_for_contract( NonNull :: add) ]
1872
1950
pub fn non_null_check_add ( ) {
@@ -1875,16 +1953,16 @@ mod verify {
1875
1953
let raw_ptr: * mut i8 = generator. any_in_bounds ( ) . ptr ;
1876
1954
let ptr = unsafe { NonNull :: new ( raw_ptr) . unwrap ( ) } ;
1877
1955
// Create a non-deterministic count value
1878
- let count: usize = kani:: any ( ) ;
1879
-
1956
+ let count: usize = kani:: any ( ) ;
1957
+
1880
1958
unsafe {
1881
1959
let result = ptr. add ( count) ;
1882
1960
}
1883
1961
}
1884
1962
1885
1963
// pub fn addr(self) -> NonZero<usize>
1886
1964
#[ kani:: proof_for_contract( NonNull :: addr) ]
1887
- pub fn non_null_check_addr ( ) {
1965
+ pub fn non_null_check_addr ( ) {
1888
1966
// Create NonNull pointer & get pointer address
1889
1967
let x = kani:: any :: < usize > ( ) as * mut i32 ;
1890
1968
let Some ( nonnull_xptr) = NonNull :: new ( x) else { return ; } ;
@@ -1897,7 +1975,7 @@ mod verify {
1897
1975
// Create NonNull pointer
1898
1976
let x = kani:: any :: < usize > ( ) as * mut i32 ;
1899
1977
let Some ( nonnull_xptr) = NonNull :: new ( x) else { return ; } ;
1900
-
1978
+
1901
1979
// Call align_offset with valid align value
1902
1980
let align: usize = kani:: any ( ) ;
1903
1981
kani:: assume ( align. is_power_of_two ( ) ) ;
@@ -1914,7 +1992,7 @@ mod verify {
1914
1992
1915
1993
// Generate align value that is not necessarily a power of two
1916
1994
let invalid_align: usize = kani:: any ( ) ;
1917
-
1995
+
1918
1996
// Trigger panic
1919
1997
let offset = nonnull_xptr. align_offset ( invalid_align) ;
1920
1998
}
0 commit comments