@@ -43,6 +43,12 @@ use crate::convert::TryInto as _;
43
43
use crate :: slice:: memchr;
44
44
use crate :: { cmp, fmt} ;
45
45
46
+ #[ cfg( all( target_arch = "x86_64" , any( kani, target_feature = "sse2" ) ) ) ]
47
+ use safety:: { loop_invariant, requires} ;
48
+
49
+ #[ cfg( kani) ]
50
+ use crate :: kani;
51
+
46
52
// Pattern
47
53
48
54
/// A string pattern.
@@ -1905,8 +1911,9 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
1905
1911
/// # Safety
1906
1912
///
1907
1913
/// Both slices must have the same length.
1908
- #[ cfg( all( target_arch = "x86_64" , target_feature = "sse2" ) ) ] // only called on x86
1914
+ #[ cfg( all( target_arch = "x86_64" , any ( kani , target_feature = "sse2" ) ) ) ] // only called on x86
1909
1915
#[ inline]
1916
+ #[ requires( x. len( ) == y. len( ) ) ]
1910
1917
unsafe fn small_slice_eq ( x : & [ u8 ] , y : & [ u8 ] ) -> bool {
1911
1918
debug_assert_eq ! ( x. len( ) , y. len( ) ) ;
1912
1919
// This function is adapted from
@@ -1951,6 +1958,11 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
1951
1958
unsafe {
1952
1959
let ( mut px, mut py) = ( x. as_ptr ( ) , y. as_ptr ( ) ) ;
1953
1960
let ( pxend, pyend) = ( px. add ( x. len ( ) - 4 ) , py. add ( y. len ( ) - 4 ) ) ;
1961
+ #[ loop_invariant( crate :: ub_checks:: same_allocation( x. as_ptr( ) , px)
1962
+ && crate :: ub_checks:: same_allocation( y. as_ptr( ) , py)
1963
+ && px. addr( ) >= x. as_ptr( ) . addr( )
1964
+ && py. addr( ) >= y. as_ptr( ) . addr( )
1965
+ && px. addr( ) - x. as_ptr( ) . addr( ) == py. addr( ) - y. as_ptr( ) . addr( ) ) ]
1954
1966
while px < pxend {
1955
1967
let vx = ( px as * const u32 ) . read_unaligned ( ) ;
1956
1968
let vy = ( py as * const u32 ) . read_unaligned ( ) ;
@@ -1965,3 +1977,50 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
1965
1977
vx == vy
1966
1978
}
1967
1979
}
1980
+
1981
+ #[ cfg( kani) ]
1982
+ #[ unstable( feature = "kani" , issue = "none" ) ]
1983
+ pub mod verify {
1984
+ use super :: * ;
1985
+
1986
+ #[ cfg( all( kani, target_arch = "x86_64" ) ) ] // only called on x86
1987
+ #[ kani:: proof]
1988
+ #[ kani:: unwind( 4 ) ]
1989
+ pub fn check_small_slice_eq ( ) {
1990
+ // TODO: ARR_SIZE can be `std::usize::MAX` with cbmc argument
1991
+ // `--arrays-uf-always`
1992
+ const ARR_SIZE : usize = 1000 ;
1993
+ let x: [ u8 ; ARR_SIZE ] = kani:: any ( ) ;
1994
+ let y: [ u8 ; ARR_SIZE ] = kani:: any ( ) ;
1995
+ let xs = kani:: slice:: any_slice_of_array ( & x) ;
1996
+ let ys = kani:: slice:: any_slice_of_array ( & y) ;
1997
+ kani:: assume ( xs. len ( ) == ys. len ( ) ) ;
1998
+ unsafe {
1999
+ small_slice_eq ( xs, ys) ;
2000
+ }
2001
+ }
2002
+
2003
+ /* This harness check `small_slice_eq` with dangling pointer to slice
2004
+ with zero size. Kani finds safety issue of `small_slice_eq` in this
2005
+ harness and hence the proof will fail.
2006
+
2007
+ #[cfg(all(kani, target_arch = "x86_64"))] // only called on x86
2008
+ #[kani::proof]
2009
+ #[kani::unwind(4)]
2010
+ pub fn check_small_slice_eq_empty() {
2011
+ let ptr_x = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
2012
+ let ptr_y = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
2013
+ kani::assume(ptr_x.is_aligned());
2014
+ kani::assume(ptr_y.is_aligned());
2015
+ assert_eq!(
2016
+ unsafe {
2017
+ small_slice_eq(
2018
+ crate::slice::from_raw_parts(ptr_x, 0),
2019
+ crate::slice::from_raw_parts(ptr_y, 0),
2020
+ )
2021
+ },
2022
+ true
2023
+ );
2024
+ }
2025
+ */
2026
+ }
0 commit comments