Skip to content

Commit 00169b7

Browse files
Close Challenges 6 & 14; remove optional correctness work in Challenge 12 (#247)
In this PR, I refined the existing challenges by: - Added the missing contracts and harnesses for 3 functions write, write_bytes, write_unaligned for the NonNull challenge, then changed the status of this challenge to "resolved". - Edited some descriptions of smallsort - Removed the (optional) correctness checking in NonZero challenge. - Resolved the Safety of Primitive Conversions challenge. I don't add more functions to existing challenge to keep each challenge under manageable size. I will create other challenges for functions inside the same modules as the existing ones. Resolves #53 Resolves #220 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: Carolyn Zech <[email protected]>
1 parent ebae8ab commit 00169b7

File tree

5 files changed

+256
-30
lines changed

5 files changed

+256
-30
lines changed

doc/src/challenges/0006-nonnull.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Challenge 6: Safety of NonNull
22

3-
- **Status:** Open
3+
- **Status:** Resolved
44
- **Tracking Issue:** [#53](https://github.com/model-checking/verify-rust-std/issues/53)
55
- **Start date:** *2024/08/16*
66
- **End date:** *2025/04/10*
77
- **Reward:** *N/A*
8-
8+
- **Contributors**: [Quinyuan Wu](https://github.com/QinyuanWu), [Daniel Tu](https://github.com/danielhumanmod), [Dhvani Kapadia](https://github.com/Dhvani-Kapadia) and [Jiun Chi Yang](https://github.com/Jimmycreative)
99
-------------------
1010

1111

doc/src/challenges/0008-smallsort.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111

1212
## Goal
1313

14-
The implementations of the traits `StableSmallSortTypeImpl`, `UnstableSmallSortTypeImpl`, and `UnstableSmallSortFreezeTypeImpl` in the `smallsort` [module](https://github.com/rust-lang/rust/blob/master/library/core/src/slice/sort/shared/smallsort.rs) of the Rust standard library are the sorting
15-
algorithms optimized for slices with small lengths.
14+
The implementations of the traits `StableSmallSortTypeImpl`, `UnstableSmallSortTypeImpl`, and `UnstableSmallSortFreezeTypeImpl` in the `smallsort` [module](https://github.com/rust-lang/rust/blob/master/library/core/src/slice/sort/shared/smallsort.rs) of the Rust standard library are the sorting algorithms with optimized implementations for slices with small lengths.
1615
In this challenge, the goal is to, first prove the memory safety of the public functions in the `smallsort` module, and, second, write contracts for them to
1716
show that the sorting algorithms actually sort the slices.
1817

doc/src/challenges/0012-nonzero.md

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ Verify the safety of the following functions and methods (all located within `co
7373
| `from_mut` |
7474
| `from_mut_unchecked` |
7575

76-
You are not required to write correctness contracts for these methods (e.g., for `max`, ensuring that the `result` is indeed the maximum of the inputs), but it would be great to do so!
7776

7877
### List of UBs
7978

doc/src/challenges/0014-convert-num.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Challenge 14: Safety of Primitive Conversions
22

3-
- **Status:** Open
3+
- **Status:** Resolved
44
- **Tracking Issue:** https://github.com/model-checking/verify-rust-std/issues/220
55
- **Start date:** 2024/12/15
66
- **End date:** 2025/2/28
77
- **Prize:** *TBD*
8-
8+
- **Contributors**: [Shoyu Vanilla](https://github.com/ShoyuVanilla)
99
-------------------
1010

1111
## Goal

library/core/src/ptr/non_null.rs

+251-23
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,8 @@ impl<T: ?Sized> NonNull<T> {
12101210
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12111211
#[stable(feature = "non_null_convenience", since = "1.80.0")]
12121212
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
1213+
#[cfg_attr(kani, kani::modifies(self.as_ptr()))]
1214+
#[requires(ub_checks::can_write(self.as_ptr()))]
12131215
pub const unsafe fn write(self, val: T)
12141216
where
12151217
T: Sized,
@@ -1229,6 +1231,13 @@ impl<T: ?Sized> NonNull<T> {
12291231
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12301232
#[stable(feature = "non_null_convenience", since = "1.80.0")]
12311233
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
1234+
#[cfg_attr(kani, kani::modifies(crate::ptr::slice_from_raw_parts(self.as_ptr(), count)))]
1235+
#[requires(
1236+
count.checked_mul(core::mem::size_of::<T>() as usize).is_some_and(|byte_count| byte_count.wrapping_add(self.as_ptr() as usize) <= isize::MAX as usize) &&
1237+
ub_checks::can_write(core::ptr::slice_from_raw_parts_mut(self.as_ptr(), count))
1238+
)]
1239+
#[ensures(|_|
1240+
ub_checks::can_dereference(crate::ptr::slice_from_raw_parts(self.as_ptr() as *const u8, count * size_of::<T>())))]
12321241
pub const unsafe fn write_bytes(self, val: u8, count: usize)
12331242
where
12341243
T: Sized,
@@ -1272,6 +1281,8 @@ impl<T: ?Sized> NonNull<T> {
12721281
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12731282
#[stable(feature = "non_null_convenience", since = "1.80.0")]
12741283
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
1284+
#[cfg_attr(kani, kani::modifies(self.as_ptr()))]
1285+
#[requires(ub_checks::can_write_unaligned(self.as_ptr()))]
12751286
pub const unsafe fn write_unaligned(self, val: T)
12761287
where
12771288
T: Sized,
@@ -2531,12 +2542,143 @@ mod verify {
25312542
}
25322543
}
25332544

2545+
macro_rules! generate_write_harness {
2546+
($type:ty, $harness_name:ident) => {
2547+
#[kani::proof_for_contract(NonNull::write)]
2548+
pub fn $harness_name() {
2549+
// Create a pointer generator for the given type with appropriate byte size
2550+
const ARR_SIZE: usize = mem::size_of::<$type>() * 100;
2551+
let mut generator = kani::PointerGenerator::<ARR_SIZE>::new();
2552+
2553+
// Get a raw pointer from the generator
2554+
let raw_ptr: *mut $type = generator.any_in_bounds().ptr;
2555+
2556+
// Create a non-null pointer from the raw pointer
2557+
let ptr = NonNull::new(raw_ptr).unwrap();
2558+
2559+
// Create a non-deterministic value to write
2560+
let new_value: $type = kani::any();
2561+
2562+
unsafe {
2563+
// Perform the volatile write operation
2564+
ptr.write(new_value);
2565+
2566+
// Read back the value and assert it's correct
2567+
assert_eq!(ptr.as_ptr().read(), new_value);
2568+
}
2569+
}
2570+
};
2571+
}
2572+
2573+
#[kani::proof_for_contract(NonNull::write)]
2574+
pub fn non_null_check_write_unit() {
2575+
// Create a pointer generator for the given type with appropriate byte size
2576+
let mut generator = kani::PointerGenerator::<1>::new();
2577+
2578+
// Get a raw pointer from the generator
2579+
let raw_ptr: *mut () = generator.any_in_bounds().ptr;
2580+
2581+
// Create a non-null pointer from the raw pointer
2582+
let ptr = NonNull::new(raw_ptr).unwrap();
2583+
2584+
// Create a non-deterministic value to write
2585+
let new_value: () = kani::any();
2586+
2587+
unsafe {
2588+
// Perform the volatile write operation
2589+
ptr.write(new_value);
2590+
2591+
// Read back the value and assert it's correct
2592+
assert_eq!(ptr.as_ptr().read(), new_value);
2593+
}
2594+
}
2595+
2596+
// Generate proof harnesses for multiple types with appropriate byte sizes
2597+
generate_write_harness!(i8, non_null_check_write_i8);
2598+
generate_write_harness!(i16, non_null_check_write_i16);
2599+
generate_write_harness!(i32, non_null_check_write_i32);
2600+
generate_write_harness!(i64, non_null_check_write_i64);
2601+
generate_write_harness!(i128, non_null_check_write_i128);
2602+
generate_write_harness!(isize, non_null_check_write_isize);
2603+
generate_write_harness!(u8, non_null_check_write_u8);
2604+
generate_write_harness!(u16, non_null_check_write_u16);
2605+
generate_write_harness!(u32, non_null_check_write_u32);
2606+
generate_write_harness!(u64, non_null_check_write_u64);
2607+
generate_write_harness!(u128, non_null_check_write_u128);
2608+
generate_write_harness!(usize, non_null_check_write_usize);
2609+
2610+
macro_rules! generate_write_unaligned_harness {
2611+
($type:ty, $harness_name:ident) => {
2612+
#[kani::proof_for_contract(NonNull::write_unaligned)]
2613+
pub fn $harness_name() {
2614+
// Create a pointer generator for the given type with appropriate byte size
2615+
const ARR_SIZE: usize = mem::size_of::<$type>() * 100;
2616+
let mut generator = kani::PointerGenerator::<ARR_SIZE>::new();
2617+
2618+
// Get a raw pointer from the generator
2619+
let raw_ptr: *mut $type = generator.any_in_bounds().ptr;
2620+
2621+
// Create a non-null pointer from the raw pointer
2622+
let ptr = NonNull::new(raw_ptr).unwrap();
2623+
2624+
// Create a non-deterministic value to write
2625+
let new_value: $type = kani::any();
2626+
2627+
unsafe {
2628+
// Perform the volatile write operation
2629+
ptr.write_unaligned(new_value);
2630+
2631+
// Read back the value and assert it's correct
2632+
assert_eq!(ptr.as_ptr().read_unaligned(), new_value);
2633+
}
2634+
}
2635+
};
2636+
}
2637+
2638+
#[kani::proof_for_contract(NonNull::write_unaligned)]
2639+
pub fn non_null_check_write_unaligned_unit() {
2640+
// Create a pointer generator for the given type with appropriate byte size
2641+
let mut generator = kani::PointerGenerator::<1>::new();
2642+
2643+
// Get a raw pointer from the generator
2644+
let raw_ptr: *mut () = generator.any_in_bounds().ptr;
2645+
2646+
// Create a non-null pointer from the raw pointer
2647+
let ptr = NonNull::new(raw_ptr).unwrap();
2648+
2649+
// Create a non-deterministic value to write
2650+
let new_value: () = kani::any();
2651+
2652+
unsafe {
2653+
// Perform the volatile write operation
2654+
ptr.write_unaligned(new_value);
2655+
2656+
// Read back the value and assert it's correct
2657+
assert_eq!(ptr.as_ptr().read_unaligned(), new_value);
2658+
}
2659+
}
2660+
2661+
// Generate proof harnesses for multiple types with appropriate byte sizes
2662+
generate_write_unaligned_harness!(i8, non_null_check_write_unaligned_i8);
2663+
generate_write_unaligned_harness!(i16, non_null_check_write_unaligned_i16);
2664+
generate_write_unaligned_harness!(i32, non_null_check_write_unaligned_i32);
2665+
generate_write_unaligned_harness!(i64, non_null_check_write_unaligned_i64);
2666+
generate_write_unaligned_harness!(i128, non_null_check_write_unaligned_i128);
2667+
generate_write_unaligned_harness!(isize, non_null_check_write_unaligned_isize);
2668+
generate_write_unaligned_harness!(u8, non_null_check_write_unaligned_u8);
2669+
generate_write_unaligned_harness!(u16, non_null_check_write_unaligned_u16);
2670+
generate_write_unaligned_harness!(u32, non_null_check_write_unaligned_u32);
2671+
generate_write_unaligned_harness!(u64, non_null_check_write_unaligned_u64);
2672+
generate_write_unaligned_harness!(u128, non_null_check_write_unaligned_u128);
2673+
generate_write_unaligned_harness!(usize, non_null_check_write_unaligned_usize);
2674+
25342675
macro_rules! generate_write_volatile_harness {
2535-
($type:ty, $byte_size:expr, $harness_name:ident) => {
2676+
($type:ty, $harness_name:ident) => {
25362677
#[kani::proof_for_contract(NonNull::write_volatile)]
25372678
pub fn $harness_name() {
25382679
// Create a pointer generator for the given type with appropriate byte size
2539-
let mut generator = kani::PointerGenerator::<$byte_size>::new();
2680+
const ARR_SIZE: usize = mem::size_of::<$type>() * 100;
2681+
let mut generator = kani::PointerGenerator::<ARR_SIZE>::new();
25402682

25412683
// Get a raw pointer from the generator
25422684
let raw_ptr: *mut $type = generator.any_in_bounds().ptr;
@@ -2558,28 +2700,114 @@ mod verify {
25582700
};
25592701
}
25602702

2703+
#[kani::proof_for_contract(NonNull::write_volatile)]
2704+
pub fn non_null_check_write_volatile_unit() {
2705+
// Create a pointer generator for the given type with appropriate byte size
2706+
let mut generator = kani::PointerGenerator::<1>::new();
2707+
2708+
// Get a raw pointer from the generator
2709+
let raw_ptr: *mut () = generator.any_in_bounds().ptr;
2710+
2711+
// Create a non-null pointer from the raw pointer
2712+
let ptr = NonNull::new(raw_ptr).unwrap();
2713+
2714+
// Create a non-deterministic value to write
2715+
let new_value: () = kani::any();
2716+
2717+
unsafe {
2718+
// Perform the volatile write operation
2719+
ptr.write_volatile(new_value);
2720+
2721+
// Read back the value and assert it's correct
2722+
assert_eq!(ptr.as_ptr().read_volatile(), new_value);
2723+
}
2724+
}
2725+
2726+
// Generate proof harnesses for multiple types with appropriate byte sizes
2727+
generate_write_volatile_harness!(i8, non_null_check_write_volatile_i8);
2728+
generate_write_volatile_harness!(i16, non_null_check_write_volatile_i16);
2729+
generate_write_volatile_harness!(i32, non_null_check_write_volatile_i32);
2730+
generate_write_volatile_harness!(i64, non_null_check_write_volatile_i64);
2731+
generate_write_volatile_harness!(i128, non_null_check_write_volatile_i128);
2732+
generate_write_volatile_harness!(isize, non_null_check_write_volatile_isize);
2733+
generate_write_volatile_harness!(u8, non_null_check_write_volatile_u8);
2734+
generate_write_volatile_harness!(u16, non_null_check_write_volatile_u16);
2735+
generate_write_volatile_harness!(u32, non_null_check_write_volatile_u32);
2736+
generate_write_volatile_harness!(u64, non_null_check_write_volatile_u64);
2737+
generate_write_volatile_harness!(u128, non_null_check_write_volatile_u128);
2738+
generate_write_volatile_harness!(usize, non_null_check_write_volatile_usize);
2739+
2740+
macro_rules! generate_write_bytes_harness {
2741+
($type:ty, $harness_name:ident) => {
2742+
#[kani::proof_for_contract(NonNull::write_bytes)]
2743+
pub fn $harness_name() {
2744+
// Create a pointer generator for the given type with appropriate byte size
2745+
const ARR_SIZE: usize = mem::size_of::<$type>() * 10;
2746+
let mut generator = kani::PointerGenerator::<ARR_SIZE>::new();
2747+
2748+
// Get a raw pointer from the generator
2749+
let raw_ptr: *mut $type = generator.any_in_bounds().ptr;
2750+
2751+
// Create a non-null pointer from the raw pointer
2752+
let ptr = NonNull::new(raw_ptr).unwrap();
2753+
2754+
// Create a non-deterministic value to write
2755+
let val: u8 = kani::any();
2756+
2757+
// Create a non-deterministic count
2758+
let count: usize = kani::any();
2759+
2760+
unsafe {
2761+
// Perform the volatile write operation
2762+
ptr.write_bytes(val, count);
2763+
2764+
// Create a non-deterministic count
2765+
let i: usize = kani::any_where(|&x| x < count * mem::size_of::<$type>());
2766+
let ptr_byte = ptr.as_ptr() as *const u8;
2767+
2768+
// Read back the value and assert it's correct
2769+
assert_eq!(*ptr_byte.add(i), val);
2770+
}
2771+
}
2772+
};
2773+
}
2774+
2775+
#[kani::proof_for_contract(NonNull::write_bytes)]
2776+
pub fn non_null_check_write_bytes_unit() {
2777+
// Create a pointer generator for the given type with appropriate byte size
2778+
let mut generator = kani::PointerGenerator::<1>::new();
2779+
2780+
// Get a raw pointer from the generator
2781+
let raw_ptr: *mut () = generator.any_in_bounds().ptr;
2782+
2783+
// Create a non-null pointer from the raw pointer
2784+
let ptr = NonNull::new(raw_ptr).unwrap();
2785+
2786+
// Create a non-deterministic value to write
2787+
let val: u8 = kani::any();
2788+
2789+
// Create a non-deterministic count
2790+
let count: usize = kani::any();
2791+
2792+
unsafe {
2793+
// Perform the volatile write operation
2794+
ptr.write_bytes(val, count);
2795+
}
2796+
}
2797+
25612798
// Generate proof harnesses for multiple types with appropriate byte sizes
2562-
generate_write_volatile_harness!(i8, 1, non_null_check_write_volatile_i8);
2563-
generate_write_volatile_harness!(i16, 2, non_null_check_write_volatile_i16);
2564-
generate_write_volatile_harness!(i32, 4, non_null_check_write_volatile_i32);
2565-
generate_write_volatile_harness!(i64, 8, non_null_check_write_volatile_i64);
2566-
generate_write_volatile_harness!(i128, 16, non_null_check_write_volatile_i128);
2567-
generate_write_volatile_harness!(
2568-
isize,
2569-
{ core::mem::size_of::<isize>() },
2570-
non_null_check_write_volatile_isize
2571-
);
2572-
generate_write_volatile_harness!(u8, 1, non_null_check_write_volatile_u8);
2573-
generate_write_volatile_harness!(u16, 2, non_null_check_write_volatile_u16);
2574-
generate_write_volatile_harness!(u32, 4, non_null_check_write_volatile_u32);
2575-
generate_write_volatile_harness!(u64, 8, non_null_check_write_volatile_u64);
2576-
generate_write_volatile_harness!(u128, 16, non_null_check_write_volatile_u128);
2577-
generate_write_volatile_harness!(
2578-
usize,
2579-
{ core::mem::size_of::<usize>() },
2580-
non_null_check_write_volatile_usize
2581-
);
2582-
generate_write_volatile_harness!((), 1, non_null_check_write_volatile_unit);
2799+
generate_write_bytes_harness!(i8, non_null_check_write_bytes_i8);
2800+
generate_write_bytes_harness!(i16, non_null_check_write_bytes_i16);
2801+
generate_write_bytes_harness!(i32, non_null_check_write_bytes_i32);
2802+
generate_write_bytes_harness!(i64, non_null_check_write_bytes_i64);
2803+
generate_write_bytes_harness!(i128, non_null_check_write_bytes_i128);
2804+
generate_write_bytes_harness!(isize, non_null_check_write_bytes_isize);
2805+
generate_write_bytes_harness!(u8, non_null_check_write_bytes_u8);
2806+
generate_write_bytes_harness!(u16, non_null_check_write_bytes_u16);
2807+
generate_write_bytes_harness!(u32, non_null_check_write_bytes_u32);
2808+
generate_write_bytes_harness!(u64, non_null_check_write_bytes_u64);
2809+
generate_write_bytes_harness!(u128, non_null_check_write_bytes_u128);
2810+
generate_write_bytes_harness!(usize, non_null_check_write_bytes_usize);
25832811

25842812
#[kani::proof_for_contract(NonNull::byte_add)]
25852813
pub fn non_null_byte_add_proof() {

0 commit comments

Comments
 (0)