@@ -15,6 +15,9 @@ use crate::simd::{self, Simd};
1515use crate :: ub_checks:: assert_unsafe_precondition;
1616use crate :: { fmt, hint, ptr, slice} ;
1717
18+ #[ cfg( kani) ]
19+ use crate :: kani;
20+
1821#[ unstable(
1922 feature = "slice_internals" ,
2023 issue = "none" ,
@@ -2777,18 +2780,20 @@ impl<T> [T] {
27772780 }
27782781 let mut base = 0usize ;
27792782
2783+ let mut cmp: Ordering = Equal ;
27802784 // This loop intentionally doesn't have an early exit if the comparison
27812785 // returns Equal. We want the number of loop iterations to depend *only*
27822786 // on the size of the input slice so that the CPU can reliably predict
27832787 // the loop count.
2788+ #[ cfg_attr( kani, kani:: loop_invariant( size <= self . len( ) && size >= 1 && base <= self . len( ) && size+base <= self . len( ) ) ) ]
27842789 while size > 1 {
27852790 let half = size / 2 ;
27862791 let mid = base + half;
27872792
27882793 // SAFETY: the call is made safe by the following inconstants:
27892794 // - `mid >= 0`: by definition
27902795 // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...`
2791- let cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
2796+ cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
27922797
27932798 // Binary search interacts poorly with branch prediction, so force
27942799 // the compiler to use conditional moves if supported by the target
@@ -4911,4 +4916,36 @@ impl<const N: usize> fmt::Display for GetManyMutError<N> {
49114916 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
49124917 fmt:: Display :: fmt ( "an index is out of bounds or appeared multiple times in the array" , f)
49134918 }
4919+ }
4920+
4921+ #[ cfg( kani) ]
4922+ #[ unstable( feature = "kani" , issue = "none" ) ]
4923+ pub mod verify {
4924+ use super :: * ;
4925+
4926+ // Copied from https://github.com/model-checking/kani/blob/main/library/kani/src/slice.rs
4927+ // should be removed when these functions are moved to `kani_core`
4928+ pub fn any_slice_of_array < T , const LENGTH : usize > ( arr : & [ T ; LENGTH ] ) -> & [ T ] {
4929+ let ( from, to) = any_range :: < LENGTH > ( ) ;
4930+ & arr[ from..to]
4931+ }
4932+
4933+ fn any_range < const LENGTH : usize > ( ) -> ( usize , usize ) {
4934+ let from: usize = kani:: any ( ) ;
4935+ let to: usize = kani:: any ( ) ;
4936+ kani:: assume ( to <= LENGTH ) ;
4937+ kani:: assume ( from <= to) ;
4938+ ( from, to)
4939+ }
4940+
4941+ #[ kani:: proof]
4942+ pub fn check_binary_search_by ( ) {
4943+ const ARR_SIZE : usize = 1000 ;
4944+ let x: [ u8 ; ARR_SIZE ] = kani:: any ( ) ;
4945+ let xs = any_slice_of_array ( & x) ;
4946+ let key: u8 = kani:: any ( ) ;
4947+ unsafe {
4948+ xs. binary_search_by ( |p| p. cmp ( & key) ) ;
4949+ }
4950+ }
49144951}
0 commit comments