-
Notifications
You must be signed in to change notification settings - Fork 62
Verifying methods of <*const T>
#92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
500f249
99701ff
31c82a9
f84b7a6
a839820
21e0ab8
b54ce9e
0c0078f
a192129
2ef5923
f1602aa
1b467d5
9461027
159137b
df56d18
eab0a15
e07040f
0ff52b5
ccd5c3c
180a276
6a85e3e
6853284
fb79caf
7d05c96
8e49dcd
9af0e39
31532c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
|
@@ -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. | ||
| #[ensures(|result| kani::mem::can_dereference(result))] | ||
| pub const unsafe fn offset(self, count: isize) -> *const T | ||
| where | ||
| T: Sized, | ||
|
|
@@ -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, | ||
|
|
@@ -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, | ||
|
|
@@ -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)] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| #[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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| // 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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., There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would update in the next PR. |
||
|
|
||
| } | ||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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
offsetguarantees the safety of the resulting pointer only when the self and the result are in bounds of that allocated object.Therefore,
countshould be bounded such thatself.addr() +/- countis 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?