Skip to content
Closed
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
500f249
Add verification contract for *const T::add and *const T::add
szlee118 Sep 13, 2024
99701ff
Update const_ptr.rs
xsxszab Sep 19, 2024
31c82a9
Merge branch 'model-checking:main' into test
stogaru Sep 19, 2024
f84b7a6
Changes generic type to i32 in proof.
stogaru Sep 19, 2024
a839820
Remove unneeded file
szlee118 Sep 20, 2024
21e0ab8
added comments for function contracts and harnesses
Sep 20, 2024
b54ce9e
Merge branch 'main' into verify/ptr_const_offset
stogaru Sep 23, 2024
0c0078f
reverted library code format change and removed unnecessary comments
xsxszab Sep 30, 2024
a192129
added macros for verifying all integer types for offset and add
xsxszab Oct 1, 2024
2ef5923
implemented function contract and integer type proofs for fn sub
xsxszab Oct 1, 2024
f1602aa
Add verification of slice type proofs for fn offset
szlee118 Oct 1, 2024
1b467d5
add TODOs for proof for contracts
xsxszab Oct 1, 2024
9461027
verified *mut T::offset for all integer types
xsxszab Oct 1, 2024
159137b
Add verification of slice type proofs for fn add and sub
szlee118 Oct 3, 2024
df56d18
Remove commented code
szlee118 Oct 3, 2024
eab0a15
removed unnecessary comments
xsxszab Oct 3, 2024
e07040f
reverted changes to mut_ptr.rs
xsxszab Oct 3, 2024
0ff52b5
removed necessary comments
xsxszab Oct 3, 2024
ccd5c3c
aligned format for mut_ptr.rs
xsxszab Oct 3, 2024
180a276
aligned format for mut_ptr.rs
xsxszab Oct 3, 2024
6a85e3e
Merge pull request #1 from stogaru/verify/ptr_const_integer_types
xsxszab Oct 3, 2024
6853284
Merge branch 'model-checking:main' into verify/ptr_const_offset
xsxszab Oct 3, 2024
fb79caf
Adds proofs for composite type - tuple
stogaru Oct 3, 2024
7d05c96
Change function proof names
stogaru Oct 3, 2024
8e49dcd
Merge pull request #2 from stogaru/verify/ptr_const_composite
stogaru Oct 3, 2024
9af0e39
Merge branch 'verify/ptr_const_offset' into verify/ptr_const_slice_type
szlee118 Oct 3, 2024
31532c9
Merge pull request #4 from stogaru/verify/ptr_const_slice_type
szlee118 Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use crate::cmp::Ordering::{Equal, Greater, Less};
use crate::intrinsics::const_eval_select;
use crate::mem::SizedTypeProperties;
use crate::slice::{self, SliceIndex};
use safety::{ensures, requires};

#[cfg(kani)]
use crate::kani;

impl<T: ?Sized> *const T {
/// Returns `true` if the pointer is null.
Expand Down Expand Up @@ -388,6 +392,10 @@ impl<T: ?Sized> *const T {
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(kani::mem::can_dereference(self))]
// TODO: Determine the valid value range for 'count' and update the precondition accordingly.
#[requires(count == 0)] // This precondition is currently a placeholder.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This precondition needs to be changed based on the valid input range agreed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate more? Is there a GitHub issue to link here? What does the documentation say? How can we "determine the valid value range for count"?

Copy link
Author

@stogaru stogaru Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem 3 in the issue here gives some details. We need to add a precondition that defines the valid input range for the count parameter. This is because the offset guarantees the safety of the resulting pointer only when the self and the result are in bounds of that allocated object.
Therefore, count should be bounded such that self.addr() +/- count is within the start and end addresses of the allocated object. However, we cannot infer the start and end addresses of the allocated object solely based on the input pointer. How can we overcome this?

#[ensures(|result| kani::mem::can_dereference(result))]
pub const unsafe fn offset(self, count: isize) -> *const T
where
T: Sized,
Expand Down Expand Up @@ -849,6 +857,10 @@ impl<T: ?Sized> *const T {
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(kani::mem::can_dereference(self))]
// TODO: Determine the valid value range for 'count' and update the precondition accordingly.
#[requires(count == 0)] // This precondition is currently a placeholder.
#[ensures(|result| kani::mem::can_dereference(result))]
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
Expand Down Expand Up @@ -924,6 +936,10 @@ impl<T: ?Sized> *const T {
#[rustc_allow_const_fn_unstable(unchecked_neg)]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(kani::mem::can_dereference(self))]
// TODO: Determine the valid value range for 'count' and update the precondition accordingly.
#[requires(count == 0)] // This precondition is currently a placeholder.
#[ensures(|result| kani::mem::can_dereference(result))]
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
Expand Down Expand Up @@ -1774,3 +1790,146 @@ impl<T: ?Sized> PartialOrd for *const T {
*self >= *other
}
}

#[cfg(kani)]
#[unstable(feature = "kani", issue = "none")]
mod verify {
use crate::kani;

#[allow(unused)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[allow(unused)] was added to suppress unused code warnings during development, but it's not necessary anymore. We'll remove it to ensure we catch any unused code warnings.


#[kani::proof_for_contract(<*const i32>::offset)]
fn check_offset_slice_i32(){
let mut arr: [i32; 5] = kani::any();
let test_ptr: *const i32 = arr.as_ptr();
let offset: isize = kani::any();

unsafe{
let new_ptr = test_ptr.offset(offset);
}
}

#[kani::proof_for_contract(<*const i32>::add)]
fn check_add_slice_i32() {
let mut arr: [i32; 5] = kani::any();
let test_ptr: *const i32 = arr.as_ptr();
let count: usize = kani::any();
unsafe {
let new_ptr = test_ptr.add(count);
}
}


#[kani::proof_for_contract(<*const i32>::sub)]
fn check_sub_slice_i32() {
let mut arr: [i32; 5] = kani::any();
let test_ptr: *const i32 = arr.as_ptr();
let count: usize = kani::any();
unsafe {
let new_ptr = test_ptr.sub(count);
}
}
Comment on lines +1801 to +1831

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Would this be extended to different types or only i32? We can avoid code repeition using a macro here as well.
  2. Why are we picking 5 for the length of the array? We need to add documentation for any magical numbers.
  3. Have you tried to use here kani::any_array?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes it could be extended to different type, here it is following the minimum requirement in challenge 3.
  2. Since the length of array must be defined, I was following the test 1
  3. kani::any_array() would still need to define the size of array, by referring to test2. However, I would use it in the next PR.


// fn <*const T>::add verification begin
macro_rules! generate_add_harness {
($type:ty, $proof_name:ident) => {
#[allow(unused)]
#[kani::proof_for_contract(<*const $type>::add)]
pub fn $proof_name() {
let mut test_val: $type = kani::any::<$type>();
let test_ptr: *const $type = &test_val;
let count: usize = kani::any();
unsafe {
test_ptr.add(count);
}
}
};
}

generate_add_harness!(i8, check_add_i8);
generate_add_harness!(i16, check_add_i16);
generate_add_harness!(i32, check_add_i32);
generate_add_harness!(i64, check_add_i64);
generate_add_harness!(i128, check_add_i128);
generate_add_harness!(isize, check_add_isize);
generate_add_harness!(u8, check_add_u8);
generate_add_harness!(u16, check_add_u16);
generate_add_harness!(u32, check_add_u32);
generate_add_harness!(u64, check_add_u64);
generate_add_harness!(u128, check_add_u128);
generate_add_harness!(usize, check_add_usize);
generate_add_harness!((i8, i8), check_add_tuple_1);
generate_add_harness!((f64, bool), check_add_tuple_2);
generate_add_harness!((i32, f64, bool), check_add_tuple_3);
generate_add_harness!((i8, u16, i32, u64, isize), check_add_tuple_4);
// fn <*const T>::add verification end

// fn <*const T>::sub verification begin
macro_rules! generate_sub_harness {
($type:ty, $proof_name:ident) => {
#[allow(unused)]
#[kani::proof_for_contract(<*const $type>::sub)]
pub fn $proof_name() {
let mut test_val: $type = kani::any::<$type>();
let test_ptr: *const $type = &test_val;
let count: usize = kani::any();
unsafe {
test_ptr.sub(count);
}
}
};
}

generate_sub_harness!(i8, check_sub_i8);
generate_sub_harness!(i16, check_sub_i16);
generate_sub_harness!(i32, check_sub_i32);
generate_sub_harness!(i64, check_sub_i64);
generate_sub_harness!(i128, check_sub_i128);
generate_sub_harness!(isize, check_sub_isize);
generate_sub_harness!(u8, check_sub_u8);
generate_sub_harness!(u16, check_sub_u16);
generate_sub_harness!(u32, check_sub_u32);
generate_sub_harness!(u64, check_sub_u64);
generate_sub_harness!(u128, check_sub_u128);
generate_sub_harness!(usize, check_sub_usize);
generate_sub_harness!((i8, i8), check_sub_tuple_1);
generate_sub_harness!((f64, bool), check_sub_tuple_2);
generate_sub_harness!((i32, f64, bool), check_sub_tuple_3);
generate_sub_harness!((i8, u16, i32, u64, isize), check_sub_tuple_4);
// fn <*const T>::sub verification end

// fn <*const T>::offset verification begin
macro_rules! generate_offset_harness {
($type:ty, $proof_name:ident) => {
#[allow(unused)]
#[kani::proof_for_contract(<*const $type>::offset)]
pub fn $proof_name() {
let mut test_val: $type = kani::any::<$type>();
let test_ptr: *const $type = &test_val;
let count: isize = kani::any();
unsafe {
test_ptr.offset(count);
}
}
};
}

generate_offset_harness!(i8, check_offset_i8);
generate_offset_harness!(i16, check_offset_i16);
generate_offset_harness!(i32, check_offset_i32);
generate_offset_harness!(i64, check_offset_i64);
generate_offset_harness!(i128, check_offset_i128);
generate_offset_harness!(isize, check_offset_isize);
generate_offset_harness!(u8, check_offset_u8);
generate_offset_harness!(u16, check_offset_u16);
generate_offset_harness!(u32, check_offset_u32);
generate_offset_harness!(u64, check_offset_u64);
generate_offset_harness!(u128, check_offset_u128);
generate_offset_harness!(usize, check_offset_usize);
generate_offset_harness!((i8, i8), check_offset_tuple_1);
generate_offset_harness!((f64, bool), check_offset_tuple_2);
generate_offset_harness!((i32, f64, bool), check_offset_tuple_3);
generate_offset_harness!((i8, u16, i32, u64, isize), check_offset_tuple_4);
// fn <*const T>::offset verification end
Comment on lines +1833 to +1933

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should go at the top of each code block. Also, you can consolidate all three macros into a single declarative macro using a parameter to specify the type of pointer operation (i.e., add, sub, or offset).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would update in the next PR.


}