@@ -43,6 +43,12 @@ use crate::convert::TryInto as _;
4343use crate :: slice:: memchr;
4444use crate :: { cmp, fmt} ;
4545
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+
4652// Pattern
4753
4854/// A string pattern.
@@ -1905,8 +1911,9 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
19051911/// # Safety
19061912///
19071913/// 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
19091915#[ inline]
1916+ #[ requires( x. len( ) == y. len( ) ) ]
19101917unsafe fn small_slice_eq ( x : & [ u8 ] , y : & [ u8 ] ) -> bool {
19111918 debug_assert_eq ! ( x. len( ) , y. len( ) ) ;
19121919 // This function is adapted from
@@ -1951,6 +1958,11 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
19511958 unsafe {
19521959 let ( mut px, mut py) = ( x. as_ptr ( ) , y. as_ptr ( ) ) ;
19531960 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( ) ) ]
19541966 while px < pxend {
19551967 let vx = ( px as * const u32 ) . read_unaligned ( ) ;
19561968 let vy = ( py as * const u32 ) . read_unaligned ( ) ;
@@ -1965,3 +1977,50 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
19651977 vx == vy
19661978 }
19671979}
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