Skip to content

Commit d9780d6

Browse files
CStr Invariant proofs for bytes, as_ptr, to_str (#192)
Towards #150 Verifies that the CStr safety invariant holds after calling : `bytes core::ffi::c_str` `to_str core::ffi::c_str` `as_ptr core::ffi::c_str` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Yenyun035 <[email protected]> Co-authored-by: Yenyun035 <[email protected]>
1 parent d0d9de2 commit d9780d6

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

library/core/src/ffi/c_str.rs

+62
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,68 @@ mod verify {
886886
}
887887
}
888888

889+
// pub fn bytes(&self) -> Bytes<'_>
890+
#[kani::proof]
891+
#[kani::unwind(32)]
892+
fn check_bytes() {
893+
const MAX_SIZE: usize = 32;
894+
let string: [u8; MAX_SIZE] = kani::any();
895+
let slice = kani::slice::any_slice_of_array(&string);
896+
let c_str = arbitrary_cstr(slice);
897+
898+
let bytes_iterator = c_str.bytes();
899+
let bytes_expected = c_str.to_bytes();
900+
901+
// Compare the bytes obtained from the iterator and the slice
902+
// bytes_expected.iter().copied() converts the slice into an iterator over u8
903+
assert!(bytes_iterator.eq(bytes_expected.iter().copied()));
904+
assert!(c_str.is_safe());
905+
}
906+
907+
// pub const fn to_str(&self) -> Result<&str, str::Utf8Error>
908+
#[kani::proof]
909+
#[kani::unwind(32)]
910+
fn check_to_str() {
911+
const MAX_SIZE: usize = 32;
912+
let string: [u8; MAX_SIZE] = kani::any();
913+
let slice = kani::slice::any_slice_of_array(&string);
914+
let c_str = arbitrary_cstr(slice);
915+
916+
// a double conversion here and assertion, if the bytes are still the same, function is valid
917+
let str_result = c_str.to_str();
918+
if let Ok(s) = str_result {
919+
assert_eq!(s.as_bytes(), c_str.to_bytes());
920+
}
921+
assert!(c_str.is_safe());
922+
}
923+
924+
// pub const fn as_ptr(&self) -> *const c_char
925+
#[kani::proof]
926+
#[kani::unwind(33)]
927+
fn check_as_ptr() {
928+
const MAX_SIZE: usize = 32;
929+
let string: [u8; MAX_SIZE] = kani::any();
930+
let slice = kani::slice::any_slice_of_array(&string);
931+
let c_str = arbitrary_cstr(slice);
932+
933+
let ptr = c_str.as_ptr();
934+
let bytes_with_nul = c_str.to_bytes_with_nul();
935+
let len = bytes_with_nul.len();
936+
937+
// We ensure that `ptr` is valid for reads of `len` bytes
938+
unsafe {
939+
for i in 0..len {
940+
// Iterate and get each byte in the C string from our raw ptr
941+
let byte_at_ptr = *ptr.add(i);
942+
// Get the byte at every pos
943+
let byte_in_cstr = bytes_with_nul[i];
944+
// Compare the two bytes to ensure they are equal
945+
assert_eq!(byte_at_ptr as u8, byte_in_cstr);
946+
}
947+
}
948+
assert!(c_str.is_safe());
949+
}
950+
889951
#[kani::proof]
890952
#[kani::unwind(17)]
891953
fn check_from_bytes_with_nul() {

0 commit comments

Comments
 (0)