Skip to content

Commit 10cfee8

Browse files
committed
Verify safety of CStr CloneToUninit and Index<RangeFrom> (Challenge 13)
Add the final 2 verification harnesses to complete Challenge 13: - check_clone_to_uninit: Verifies the unsafe CloneToUninit impl for CStr correctly copies all bytes (including NUL terminator) and produces a valid CStr at the destination. Includes safety contract on clone_to_uninit requiring non-null dest pointer. - check_index_from: Verifies ops::Index<RangeFrom<usize>> for CStr produces a valid CStr that maintains the safety invariant and matches the expected tail of the original bytes. Both harnesses are bounded (MAX_SIZE=16/32) with appropriate unwind limits and verify the CStr is_safe() invariant holds.
1 parent 9bbdb30 commit 10cfee8

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

library/core/src/clone.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
#![stable(feature = "rust1", since = "1.0.0")]
3838

3939
use crate::marker::{Destruct, PointeeSized};
40+
#[cfg(kani)]
41+
use crate::kani;
42+
use safety::requires;
4043

4144
mod uninit;
4245

@@ -544,6 +547,7 @@ unsafe impl CloneToUninit for str {
544547
#[unstable(feature = "clone_to_uninit", issue = "126799")]
545548
unsafe impl CloneToUninit for crate::ffi::CStr {
546549
#[cfg_attr(debug_assertions, track_caller)]
550+
#[requires(!dest.is_null())]
547551
unsafe fn clone_to_uninit(&self, dest: *mut u8) {
548552
// SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
549553
// And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).

library/core/src/ffi/c_str.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ impl FusedIterator for Bytes<'_> {}
875875
#[unstable(feature = "kani", issue = "none")]
876876
mod verify {
877877
use super::*;
878+
use crate::clone::CloneToUninit;
878879

879880
// Helper function
880881
fn arbitrary_cstr(slice: &[u8]) -> &CStr {
@@ -1096,4 +1097,58 @@ mod verify {
10961097
assert_eq!(expected_is_empty, c_str.is_empty());
10971098
assert!(c_str.is_safe());
10981099
}
1100+
1101+
// ops::Index<ops::RangeFrom<usize>> for CStr
1102+
#[kani::proof]
1103+
#[kani::unwind(33)]
1104+
fn check_index_from() {
1105+
const MAX_SIZE: usize = 32;
1106+
let string: [u8; MAX_SIZE] = kani::any();
1107+
let slice = kani::slice::any_slice_of_array(&string);
1108+
let c_str = arbitrary_cstr(slice);
1109+
1110+
let bytes_with_nul = c_str.to_bytes_with_nul();
1111+
let idx: usize = kani::any();
1112+
kani::assume(idx < bytes_with_nul.len());
1113+
1114+
let indexed = &c_str[idx..];
1115+
assert!(indexed.is_safe());
1116+
// The indexed result should correspond to the tail of the original bytes
1117+
assert_eq!(indexed.to_bytes_with_nul(), &bytes_with_nul[idx..]);
1118+
}
1119+
1120+
// CloneToUninit for CStr
1121+
#[kani::proof]
1122+
#[kani::unwind(17)]
1123+
fn check_clone_to_uninit() {
1124+
const MAX_SIZE: usize = 16;
1125+
let string: [u8; MAX_SIZE] = kani::any();
1126+
let slice = kani::slice::any_slice_of_array(&string);
1127+
let c_str = arbitrary_cstr(slice);
1128+
1129+
let bytes_with_nul = c_str.to_bytes_with_nul();
1130+
let len = bytes_with_nul.len();
1131+
1132+
// Allocate destination buffer
1133+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); MAX_SIZE];
1134+
let dest = buf.as_mut_ptr() as *mut u8;
1135+
1136+
// Call the unsafe clone_to_uninit
1137+
unsafe {
1138+
c_str.clone_to_uninit(dest);
1139+
}
1140+
1141+
// Verify the cloned bytes match the original
1142+
unsafe {
1143+
for i in 0..len {
1144+
assert_eq!(*dest.add(i), bytes_with_nul[i]);
1145+
}
1146+
}
1147+
1148+
// Verify we can reconstruct a valid CStr from the cloned data
1149+
let cloned_slice = unsafe { core::slice::from_raw_parts(dest, len) };
1150+
let cloned_cstr = CStr::from_bytes_with_nul(cloned_slice);
1151+
assert!(cloned_cstr.is_ok());
1152+
assert!(cloned_cstr.unwrap().is_safe());
1153+
}
10991154
}

0 commit comments

Comments
 (0)