@@ -456,6 +456,10 @@ impl CStr {
456
456
#[ stable( feature = "cstr_from_bytes" , since = "1.10.0" ) ]
457
457
#[ rustc_const_stable( feature = "const_cstr_unchecked" , since = "1.59.0" ) ]
458
458
#[ 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( ) ) ]
459
463
pub const unsafe fn from_bytes_with_nul_unchecked ( bytes : & [ u8 ] ) -> & CStr {
460
464
const_eval_select ! (
461
465
@capture { bytes: & [ u8 ] } -> & CStr :
@@ -779,6 +783,8 @@ impl AsRef<CStr> for CStr {
779
783
#[ unstable( feature = "cstr_internals" , issue = "none" ) ]
780
784
#[ cfg_attr( bootstrap, rustc_const_stable( feature = "const_cstr_from_ptr" , since = "1.81.0" ) ) ]
781
785
#[ 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 ) ]
782
788
const unsafe fn strlen ( ptr : * const c_char ) -> usize {
783
789
const_eval_select ! (
784
790
@capture { s: * const c_char = ptr } -> usize :
@@ -910,6 +916,25 @@ mod verify {
910
916
}
911
917
}
912
918
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
+
913
938
// pub fn bytes(&self) -> Bytes<'_>
914
939
#[ kani:: proof]
915
940
#[ kani:: unwind( 32 ) ]
@@ -972,6 +997,7 @@ mod verify {
972
997
assert ! ( c_str. is_safe( ) ) ;
973
998
}
974
999
1000
+ // pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>
975
1001
#[ kani:: proof]
976
1002
#[ kani:: unwind( 17 ) ]
977
1003
fn check_from_bytes_with_nul ( ) {
@@ -1042,6 +1068,18 @@ mod verify {
1042
1068
assert ! ( c_str. is_safe( ) ) ;
1043
1069
}
1044
1070
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
1045
1083
#[ kani:: proof_for_contract( CStr :: from_ptr) ]
1046
1084
#[ kani:: unwind( 33 ) ]
1047
1085
fn check_from_ptr_contract ( ) {
@@ -1052,6 +1090,7 @@ mod verify {
1052
1090
unsafe { CStr :: from_ptr ( ptr) ; }
1053
1091
}
1054
1092
1093
+ // pub const fn is_empty(&self) -> bool
1055
1094
#[ kani:: proof]
1056
1095
#[ kani:: unwind( 33 ) ]
1057
1096
fn check_is_empty ( ) {
@@ -1064,5 +1103,5 @@ mod verify {
1064
1103
let expected_is_empty = bytes. len ( ) == 0 ;
1065
1104
assert_eq ! ( expected_is_empty, c_str. is_empty( ) ) ;
1066
1105
assert ! ( c_str. is_safe( ) ) ;
1067
- }
1106
+ }
1068
1107
}
0 commit comments