@@ -456,6 +456,10 @@ impl CStr {
456456 #[ stable( feature = "cstr_from_bytes" , since = "1.10.0" ) ]
457457 #[ rustc_const_stable( feature = "const_cstr_unchecked" , since = "1.59.0" ) ]
458458 #[ rustc_allow_const_fn_unstable( const_eval_select) ]
459+ // Preconditions: Null-terminated and no intermediate null bytes
460+ #[ requires( !bytes. is_empty( ) && bytes[ bytes. len( ) - 1 ] == 0 && !bytes[ ..bytes. len( ) -1 ] . contains( & 0 ) ) ]
461+ // Postcondition: The resulting CStr satisfies the same conditions as preconditions
462+ #[ ensures( |result| result. is_safe( ) ) ]
459463 pub const unsafe fn from_bytes_with_nul_unchecked ( bytes : & [ u8 ] ) -> & CStr {
460464 const_eval_select ! (
461465 @capture { bytes: & [ u8 ] } -> & CStr :
@@ -779,6 +783,8 @@ impl AsRef<CStr> for CStr {
779783#[ unstable( feature = "cstr_internals" , issue = "none" ) ]
780784#[ cfg_attr( bootstrap, rustc_const_stable( feature = "const_cstr_from_ptr" , since = "1.81.0" ) ) ]
781785#[ rustc_allow_const_fn_unstable( const_eval_select) ]
786+ #[ requires( is_null_terminated( ptr) ) ]
787+ #[ ensures( |& result| result < isize :: MAX as usize && unsafe { * ptr. add( result) } == 0 ) ]
782788const unsafe fn strlen ( ptr : * const c_char ) -> usize {
783789 const_eval_select ! (
784790 @capture { s: * const c_char = ptr } -> usize :
@@ -910,6 +916,25 @@ mod verify {
910916 }
911917 }
912918
919+ // pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr
920+ #[ kani:: proof_for_contract( CStr :: from_bytes_with_nul_unchecked) ]
921+ #[ kani:: unwind( 33 ) ]
922+ fn check_from_bytes_with_nul_unchecked ( ) {
923+ const MAX_SIZE : usize = 32 ;
924+ let string: [ u8 ; MAX_SIZE ] = kani:: any ( ) ;
925+ let slice = kani:: slice:: any_slice_of_array ( & string) ;
926+
927+ // Kani assumes that the input slice is null-terminated and contains
928+ // no intermediate null bytes
929+ let c_str = unsafe { CStr :: from_bytes_with_nul_unchecked ( slice) } ;
930+ // Kani ensures that the output CStr holds the CStr safety invariant
931+
932+ // Correctness check
933+ let bytes = c_str. to_bytes ( ) ;
934+ let len = bytes. len ( ) ;
935+ assert_eq ! ( bytes, & slice[ ..len] ) ;
936+ }
937+
913938 // pub fn bytes(&self) -> Bytes<'_>
914939 #[ kani:: proof]
915940 #[ kani:: unwind( 32 ) ]
@@ -972,6 +997,7 @@ mod verify {
972997 assert ! ( c_str. is_safe( ) ) ;
973998 }
974999
1000+ // pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>
9751001 #[ kani:: proof]
9761002 #[ kani:: unwind( 17 ) ]
9771003 fn check_from_bytes_with_nul ( ) {
@@ -1042,6 +1068,18 @@ mod verify {
10421068 assert ! ( c_str. is_safe( ) ) ;
10431069 }
10441070
1071+ // const unsafe fn strlen(ptr: *const c_char) -> usize
1072+ #[ kani:: proof_for_contract( super :: strlen) ]
1073+ #[ kani:: unwind( 33 ) ]
1074+ fn check_strlen_contract ( ) {
1075+ const MAX_SIZE : usize = 32 ;
1076+ let mut string: [ u8 ; MAX_SIZE ] = kani:: any ( ) ;
1077+ let ptr = string. as_ptr ( ) as * const c_char ;
1078+
1079+ unsafe { super :: strlen ( ptr) ; }
1080+ }
1081+
1082+ // pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr
10451083 #[ kani:: proof_for_contract( CStr :: from_ptr) ]
10461084 #[ kani:: unwind( 33 ) ]
10471085 fn check_from_ptr_contract ( ) {
@@ -1052,6 +1090,7 @@ mod verify {
10521090 unsafe { CStr :: from_ptr ( ptr) ; }
10531091 }
10541092
1093+ // pub const fn is_empty(&self) -> bool
10551094 #[ kani:: proof]
10561095 #[ kani:: unwind( 33 ) ]
10571096 fn check_is_empty ( ) {
@@ -1064,5 +1103,5 @@ mod verify {
10641103 let expected_is_empty = bytes. len ( ) == 0 ;
10651104 assert_eq ! ( expected_is_empty, c_str. is_empty( ) ) ;
10661105 assert ! ( c_str. is_safe( ) ) ;
1067- }
1106+ }
10681107}
0 commit comments