Skip to content

Commit db71987

Browse files
Contracts & Harnesses for write_volatile (#167)
Contracts & Harnesses for `core::ptr::NonNull::write_volatile`.
1 parent 7e8a03d commit db71987

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

library/core/src/ptr/non_null.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,8 @@ impl<T: ?Sized> NonNull<T> {
11321132
#[inline(always)]
11331133
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
11341134
#[stable(feature = "non_null_convenience", since = "1.80.0")]
1135+
#[cfg_attr(kani, kani::modifies(self.as_ptr()))]
1136+
#[requires(ub_checks::can_write(self.as_ptr()))]
11351137
pub unsafe fn write_volatile(self, val: T)
11361138
where
11371139
T: Sized,
@@ -1775,7 +1777,7 @@ mod verify {
17751777
let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() };
17761778
let _ = NonNull::new(maybe_null_ptr);
17771779
}
1778-
1780+
17791781
// pub const unsafe fn read(self) -> T where T: Sized
17801782
#[kani::proof_for_contract(NonNull::read)]
17811783
pub fn non_null_check_read() {
@@ -2300,4 +2302,47 @@ mod verify {
23002302
let distance = ptr_nonnull.offset_from(origin_nonnull);
23012303
}
23022304
}
2305+
2306+
macro_rules! generate_write_volatile_harness {
2307+
($type:ty, $byte_size:expr, $harness_name:ident) => {
2308+
#[kani::proof_for_contract(NonNull::write_volatile)]
2309+
pub fn $harness_name() {
2310+
// Create a pointer generator for the given type with appropriate byte size
2311+
let mut generator = kani::PointerGenerator::<$byte_size>::new();
2312+
2313+
// Get a raw pointer from the generator
2314+
let raw_ptr: *mut $type = generator.any_in_bounds().ptr;
2315+
2316+
// Create a non-null pointer from the raw pointer
2317+
let ptr = NonNull::new(raw_ptr).unwrap();
2318+
2319+
// Create a non-deterministic value to write
2320+
let new_value: $type = kani::any();
2321+
2322+
unsafe {
2323+
// Perform the volatile write operation
2324+
ptr.write_volatile(new_value);
2325+
2326+
// Read back the value and assert it's correct
2327+
assert_eq!(ptr.as_ptr().read_volatile(), new_value);
2328+
}
2329+
}
2330+
};
2331+
}
2332+
2333+
// Generate proof harnesses for multiple types with appropriate byte sizes
2334+
generate_write_volatile_harness!(i8, 1, non_null_check_write_volatile_i8);
2335+
generate_write_volatile_harness!(i16, 2, non_null_check_write_volatile_i16);
2336+
generate_write_volatile_harness!(i32, 4, non_null_check_write_volatile_i32);
2337+
generate_write_volatile_harness!(i64, 8, non_null_check_write_volatile_i64);
2338+
generate_write_volatile_harness!(i128, 16, non_null_check_write_volatile_i128);
2339+
generate_write_volatile_harness!(isize, {core::mem::size_of::<isize>()}, non_null_check_write_volatile_isize);
2340+
generate_write_volatile_harness!(u8, 1, non_null_check_write_volatile_u8);
2341+
generate_write_volatile_harness!(u16, 2, non_null_check_write_volatile_u16);
2342+
generate_write_volatile_harness!(u32, 4, non_null_check_write_volatile_u32);
2343+
generate_write_volatile_harness!(u64, 8, non_null_check_write_volatile_u64);
2344+
generate_write_volatile_harness!(u128, 16, non_null_check_write_volatile_u128);
2345+
generate_write_volatile_harness!(usize, {core::mem::size_of::<usize>()}, non_null_check_write_volatile_usize);
2346+
generate_write_volatile_harness!((), 1, non_null_check_write_volatile_unit);
2347+
23032348
}

0 commit comments

Comments
 (0)