Skip to content

Commit 9058f0b

Browse files
CStr : Proof for from_ptr with contract (#204)
Towards #150 Similar PR Ref : #193 Annotates and verifies the safety contracts for the unsafe function : `from_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 4698b88 commit 9058f0b

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

library/core/src/ffi/c_str.rs

+34
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ use crate::marker::PhantomData;
99
use crate::ptr::NonNull;
1010
use crate::slice::memchr;
1111
use crate::{fmt, ops, slice, str};
12+
use safety::{requires, ensures};
1213

1314
use crate::ub_checks::Invariant;
15+
#[allow(unused_imports)]
16+
use crate::ub_checks::can_dereference;
1417

1518
#[cfg(kani)]
1619
use crate::kani;
@@ -229,6 +232,25 @@ impl Invariant for &CStr {
229232
}
230233
}
231234

235+
// Helper function
236+
#[cfg(kani)]
237+
#[requires(!ptr.is_null())]
238+
fn is_null_terminated(ptr: *const c_char) -> bool {
239+
let mut next = ptr;
240+
let mut found_null = false;
241+
while can_dereference(next) {
242+
if unsafe { *next == 0 } {
243+
found_null = true;
244+
break;
245+
}
246+
next = next.wrapping_add(1);
247+
}
248+
if (next.addr() - ptr.addr()) >= isize::MAX as usize {
249+
return false;
250+
}
251+
found_null
252+
}
253+
232254
impl CStr {
233255
/// Wraps a raw C string with a safe C string wrapper.
234256
///
@@ -296,6 +318,8 @@ impl CStr {
296318
#[must_use]
297319
#[stable(feature = "rust1", since = "1.0.0")]
298320
#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")]
321+
#[requires(!ptr.is_null() && is_null_terminated(ptr))]
322+
#[ensures(|result: &&CStr| result.is_safe())]
299323
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
300324
// SAFETY: The caller has provided a pointer that points to a valid C
301325
// string with a NUL terminator less than `isize::MAX` from `ptr`.
@@ -1017,6 +1041,16 @@ mod verify {
10171041
assert_eq!(bytes, &slice[..end_idx]);
10181042
assert!(c_str.is_safe());
10191043
}
1044+
1045+
#[kani::proof_for_contract(CStr::from_ptr)]
1046+
#[kani::unwind(33)]
1047+
fn check_from_ptr_contract() {
1048+
const MAX_SIZE: usize = 32;
1049+
let string: [u8; MAX_SIZE] = kani::any();
1050+
let ptr = string.as_ptr() as *const c_char;
1051+
1052+
unsafe { CStr::from_ptr(ptr); }
1053+
}
10201054

10211055
#[kani::proof]
10221056
#[kani::unwind(33)]

scripts/run-kani.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,13 @@ main() {
215215
-Z mem-predicates \
216216
-Z loop-contracts \
217217
-Z float-lib \
218-
--output-format=terse \
218+
-Z c-ffi \
219219
$command_args \
220220
--enable-unstable \
221221
--cbmc-args --object-bits 12
222222
elif [[ "$run_command" == "list" ]]; then
223223
echo "Running Kani list command..."
224-
"$kani_path" list -Z list -Z function-contracts -Z mem-predicates -Z float-lib ./library --std --format markdown
224+
"$kani_path" list -Z list -Z function-contracts -Z mem-predicates -Z float-lib -Z c-ffi ./library --std --format markdown
225225
fi
226226
}
227227

0 commit comments

Comments
 (0)