Skip to content

Commit c357e47

Browse files
using quantifiers in CStr
1 parent e411051 commit c357e47

File tree

1 file changed

+20
-33
lines changed

1 file changed

+20
-33
lines changed

library/core/src/ffi/c_str.rs

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ impl Invariant for &CStr {
204204
let bytes: &[c_char] = &self.inner;
205205
let len = bytes.len();
206206

207-
!bytes.is_empty() && bytes[len - 1] == 0 && !bytes[..len - 1].contains(&0)
207+
!bytes.is_empty()
208+
&& bytes[len - 1] == 0
209+
&& forall!(|i in (0,len - 1)| unsafe {*bytes.as_ptr().wrapping_add(i)} != 0)
208210
}
209211
}
210212

@@ -880,13 +882,13 @@ mod verify {
880882
// Helper function
881883
fn arbitrary_cstr(slice: &[u8]) -> &CStr {
882884
// At a minimum, the slice has a null terminator to form a valid CStr.
885+
let len = slice.len();
883886
kani::assume(slice.len() > 0 && slice[slice.len() - 1] == 0);
884-
let result = CStr::from_bytes_until_nul(&slice);
885-
// Given the assumption, from_bytes_until_nul should never fail
886-
assert!(result.is_ok());
887-
let c_str = result.unwrap();
888-
assert!(c_str.is_safe());
889-
c_str
887+
kani::assume(forall!(|i in (0,len-1)| unsafe {*slice.as_ptr().wrapping_add(i)} != 0));
888+
let ptr = slice.as_ptr() as *const c_char;
889+
unsafe {
890+
CStr::from_ptr(ptr);
891+
}
890892
}
891893

892894
// pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError>
@@ -908,7 +910,7 @@ mod verify {
908910

909911
// pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr
910912
#[kani::proof_for_contract(CStr::from_bytes_with_nul_unchecked)]
911-
#[kani::solver(cvc5)]
913+
#[kani::unwind(33)]
912914
fn check_from_bytes_with_nul_unchecked() {
913915
const MAX_SIZE: usize = 32;
914916
let string: [u8; MAX_SIZE] = kani::any();
@@ -927,8 +929,7 @@ mod verify {
927929

928930
// pub fn bytes(&self) -> Bytes<'_>
929931
#[kani::proof]
930-
#[kani::solver(cvc5)]
931-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
932+
#[kani::unwind(32)]
932933
fn check_bytes() {
933934
const MAX_SIZE: usize = 32;
934935
let string: [u8; MAX_SIZE] = kani::any();
@@ -946,8 +947,7 @@ mod verify {
946947

947948
// pub const fn to_str(&self) -> Result<&str, str::Utf8Error>
948949
#[kani::proof]
949-
#[kani::solver(cvc5)]
950-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
950+
#[kani::unwind(32)]
951951
fn check_to_str() {
952952
const MAX_SIZE: usize = 32;
953953
let string: [u8; MAX_SIZE] = kani::any();
@@ -964,8 +964,7 @@ mod verify {
964964

965965
// pub const fn as_ptr(&self) -> *const c_char
966966
#[kani::proof]
967-
#[kani::solver(cvc5)]
968-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
967+
#[kani::unwind(33)]
969968
fn check_as_ptr() {
970969
const MAX_SIZE: usize = 32;
971970
let string: [u8; MAX_SIZE] = kani::any();
@@ -1015,15 +1014,8 @@ mod verify {
10151014

10161015
// Non-deterministically generate a length within the valid range [0, MAX_SIZE]
10171016
let mut len: usize = kani::any_where(|&x| x < MAX_SIZE);
1018-
1019-
// If a null byte exists before the generated length
1020-
// adjust len to its position
1021-
if let Some(pos) = bytes[..len].iter().position(|&x| x == 0) {
1022-
len = pos;
1023-
} else {
1024-
// If no null byte, insert one at the chosen length
1025-
bytes[len] = 0;
1026-
}
1017+
kani::assume(forall!(|i in (0,len)| unsafe {*bytes.as_ptr().wrapping_add(i)} != 0));
1018+
bytes[len] = 0;
10271019

10281020
let c_str = CStr::from_bytes_until_nul(&bytes).unwrap();
10291021
// Verify that count_bytes matches the adjusted length
@@ -1033,8 +1025,7 @@ mod verify {
10331025

10341026
// pub const fn to_bytes(&self) -> &[u8]
10351027
#[kani::proof]
1036-
#[kani::solver(cvc5)]
1037-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
1028+
#[kani::unwind(32)]
10381029
fn check_to_bytes() {
10391030
const MAX_SIZE: usize = 32;
10401031
let string: [u8; MAX_SIZE] = kani::any();
@@ -1050,8 +1041,7 @@ mod verify {
10501041

10511042
// pub const fn to_bytes_with_nul(&self) -> &[u8]
10521043
#[kani::proof]
1053-
#[kani::solver(cvc5)]
1054-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
1044+
#[kani::unwind(33)]
10551045
fn check_to_bytes_with_nul() {
10561046
const MAX_SIZE: usize = 32;
10571047
let string: [u8; MAX_SIZE] = kani::any();
@@ -1067,8 +1057,7 @@ mod verify {
10671057

10681058
// const unsafe fn strlen(ptr: *const c_char) -> usize
10691059
#[kani::proof_for_contract(super::strlen)]
1070-
#[kani::solver(cvc5)]
1071-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
1060+
#[kani::unwind(33)]
10721061
fn check_strlen_contract() {
10731062
const MAX_SIZE: usize = 32;
10741063
let mut string: [u8; MAX_SIZE] = kani::any();
@@ -1081,8 +1070,7 @@ mod verify {
10811070

10821071
// pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr
10831072
#[kani::proof_for_contract(CStr::from_ptr)]
1084-
#[kani::solver(cvc5)]
1085-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
1073+
#[kani::unwind(33)]
10861074
fn check_from_ptr_contract() {
10871075
const MAX_SIZE: usize = 32;
10881076
let string: [u8; MAX_SIZE] = kani::any();
@@ -1095,8 +1083,7 @@ mod verify {
10951083

10961084
// pub const fn is_empty(&self) -> bool
10971085
#[kani::proof]
1098-
#[kani::solver(cvc5)]
1099-
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
1086+
#[kani::unwind(33)]
11001087
fn check_is_empty() {
11011088
const MAX_SIZE: usize = 32;
11021089
let string: [u8; MAX_SIZE] = kani::any();

0 commit comments

Comments
 (0)