Skip to content

Commit

Permalink
NonZero (rotate_left, rotate_right, max, min, clamp, count_ones, cmp)…
Browse files Browse the repository at this point in the history
… Proofs (rust-lang#202)

Working on
[rust-lang#71](model-checking#71)
(Safety of NonZero)

We are looking for feedback on our proof for rotate_left & rotate_right.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
  • Loading branch information
lang280 authored Dec 10, 2024
1 parent 8a248d9 commit 367d8ff
Showing 1 changed file with 220 additions and 0 deletions.
220 changes: 220 additions & 0 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2264,4 +2264,224 @@ mod verify {
nonzero_check!(u64, core::num::NonZeroU64, nonzero_check_new_unchecked_for_u64);
nonzero_check!(u128, core::num::NonZeroU128, nonzero_check_new_unchecked_for_u128);
nonzero_check!(usize, core::num::NonZeroUsize, nonzero_check_new_unchecked_for_usize);

macro_rules! nonzero_check_cmp {
($nonzero_type:ty, $nonzero_check_cmp_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_cmp_for() {
let x: $nonzero_type = kani::any();
let y: $nonzero_type = kani::any();
if x < y {
assert!(x.cmp(&y) == core::cmp::Ordering::Less);
} else if x > y {
assert!(x.cmp(&y) == core::cmp::Ordering::Greater);
} else {
assert!(x.cmp(&y) == core::cmp::Ordering::Equal);
}
}
};
}

// Use the macro to generate different versions of the function for multiple types
nonzero_check_cmp!(core::num::NonZeroI8, nonzero_check_cmp_for_i8);
nonzero_check_cmp!(core::num::NonZeroI16, nonzero_check_cmp_for_i16);
nonzero_check_cmp!(core::num::NonZeroI32, nonzero_check_cmp_for_i32);
nonzero_check_cmp!(core::num::NonZeroI64, nonzero_check_cmp_for_i64);
nonzero_check_cmp!(core::num::NonZeroI128, nonzero_check_cmp_for_i128);
nonzero_check_cmp!(core::num::NonZeroIsize, nonzero_check_cmp_for_isize);
nonzero_check_cmp!(core::num::NonZeroU8, nonzero_check_cmp_for_u8);
nonzero_check_cmp!(core::num::NonZeroU16, nonzero_check_cmp_for_u16);
nonzero_check_cmp!(core::num::NonZeroU32, nonzero_check_cmp_for_u32);
nonzero_check_cmp!(core::num::NonZeroU64, nonzero_check_cmp_for_u64);
nonzero_check_cmp!(core::num::NonZeroU128, nonzero_check_cmp_for_u128);
nonzero_check_cmp!(core::num::NonZeroUsize, nonzero_check_cmp_for_usize);


macro_rules! nonzero_check_max {
($nonzero_type:ty, $nonzero_check_max_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_max_for() {
let x: $nonzero_type = kani::any();
let y: $nonzero_type = kani::any();
let result = x.max(y);
if x > y {
assert!(result == x);
} else {
assert!(result == y);
}
}
};
}

nonzero_check_max!(core::num::NonZeroI8, nonzero_check_max_for_i8);
nonzero_check_max!(core::num::NonZeroI16, nonzero_check_max_for_i16);
nonzero_check_max!(core::num::NonZeroI32, nonzero_check_max_for_i32);
nonzero_check_max!(core::num::NonZeroI64, nonzero_check_max_for_i64);
nonzero_check_max!(core::num::NonZeroI128, nonzero_check_max_for_i128);
nonzero_check_max!(core::num::NonZeroIsize, nonzero_check_max_for_isize);
nonzero_check_max!(core::num::NonZeroU8, nonzero_check_max_for_u8);
nonzero_check_max!(core::num::NonZeroU16, nonzero_check_max_for_u16);
nonzero_check_max!(core::num::NonZeroU32, nonzero_check_max_for_u32);
nonzero_check_max!(core::num::NonZeroU64, nonzero_check_max_for_u64);
nonzero_check_max!(core::num::NonZeroU128, nonzero_check_max_for_u128);
nonzero_check_max!(core::num::NonZeroUsize, nonzero_check_max_for_usize);


macro_rules! nonzero_check_min {
($nonzero_type:ty, $nonzero_check_min_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_min_for() {
let x: $nonzero_type = kani::any();
let y: $nonzero_type = kani::any();
let result = x.min(y);
if x < y {
assert!(result == x);
} else {
assert!(result == y);
}
}
};
}

nonzero_check_min!(core::num::NonZeroI8, nonzero_check_min_for_i8);
nonzero_check_min!(core::num::NonZeroI16, nonzero_check_min_for_i16);
nonzero_check_min!(core::num::NonZeroI32, nonzero_check_min_for_i32);
nonzero_check_min!(core::num::NonZeroI64, nonzero_check_min_for_i64);
nonzero_check_min!(core::num::NonZeroI128, nonzero_check_min_for_i128);
nonzero_check_min!(core::num::NonZeroIsize, nonzero_check_min_for_isize);
nonzero_check_min!(core::num::NonZeroU8, nonzero_check_min_for_u8);
nonzero_check_min!(core::num::NonZeroU16, nonzero_check_min_for_u16);
nonzero_check_min!(core::num::NonZeroU32, nonzero_check_min_for_u32);
nonzero_check_min!(core::num::NonZeroU64, nonzero_check_min_for_u64);
nonzero_check_min!(core::num::NonZeroU128, nonzero_check_min_for_u128);
nonzero_check_min!(core::num::NonZeroUsize, nonzero_check_min_for_usize);


macro_rules! nonzero_check_clamp {
($nonzero_type:ty, $nonzero_check_clamp_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_clamp_for() {
let x: $nonzero_type = kani::any();
let min: $nonzero_type = kani::any();
let max: $nonzero_type = kani::any();
// Ensure min <= max, so the function should no panic
kani::assume(min <= max);
// Use the clamp function and check the result
let result = x.clamp(min, max);
if x < min {
assert!(result == min);
} else if x > max {
assert!(result == max);
} else {
assert!(result == x);
}
}
};
}

// Use the macro to generate different versions of the function for multiple types
nonzero_check_clamp!(core::num::NonZeroI8, nonzero_check_clamp_for_i8);
nonzero_check_clamp!(core::num::NonZeroI16, nonzero_check_clamp_for_16);
nonzero_check_clamp!(core::num::NonZeroI32, nonzero_check_clamp_for_32);
nonzero_check_clamp!(core::num::NonZeroI64, nonzero_check_clamp_for_64);
nonzero_check_clamp!(core::num::NonZeroI128, nonzero_check_clamp_for_128);
nonzero_check_clamp!(core::num::NonZeroIsize, nonzero_check_clamp_for_isize);
nonzero_check_clamp!(core::num::NonZeroU8, nonzero_check_clamp_for_u8);
nonzero_check_clamp!(core::num::NonZeroU16, nonzero_check_clamp_for_u16);
nonzero_check_clamp!(core::num::NonZeroU32, nonzero_check_clamp_for_u32);
nonzero_check_clamp!(core::num::NonZeroU64, nonzero_check_clamp_for_u64);
nonzero_check_clamp!(core::num::NonZeroU128, nonzero_check_clamp_for_u128);
nonzero_check_clamp!(core::num::NonZeroUsize, nonzero_check_clamp_for_usize);


macro_rules! nonzero_check_clamp_panic {
($nonzero_type:ty, $nonzero_check_clamp_for:ident) => {
#[kani::proof]
#[kani::should_panic]
pub fn $nonzero_check_clamp_for() {
let x: $nonzero_type = kani::any();
let min: $nonzero_type = kani::any();
let max: $nonzero_type = kani::any();
// Ensure min > max, so the function should panic
kani::assume(min > max);
// Use the clamp function and check the result
let result = x.clamp(min, max);
if x < min {
assert!(result == min);
} else if x > max {
assert!(result == max);
} else {
assert!(result == x);
}
}
};
}

// Use the macro to generate different versions of the function for multiple types
nonzero_check_clamp_panic!(core::num::NonZeroI8, nonzero_check_clamp_panic_for_i8);
nonzero_check_clamp_panic!(core::num::NonZeroI16, nonzero_check_clamp_panic_for_16);
nonzero_check_clamp_panic!(core::num::NonZeroI32, nonzero_check_clamp_panic_for_32);
nonzero_check_clamp_panic!(core::num::NonZeroI64, nonzero_check_clamp_panic_for_64);
nonzero_check_clamp_panic!(core::num::NonZeroI128, nonzero_check_clamp_panic_for_128);
nonzero_check_clamp_panic!(core::num::NonZeroIsize, nonzero_check_clamp_panic_for_isize);
nonzero_check_clamp_panic!(core::num::NonZeroU8, nonzero_check_clamp_panic_for_u8);
nonzero_check_clamp_panic!(core::num::NonZeroU16, nonzero_check_clamp_panic_for_u16);
nonzero_check_clamp_panic!(core::num::NonZeroU32, nonzero_check_clamp_panic_for_u32);
nonzero_check_clamp_panic!(core::num::NonZeroU64, nonzero_check_clamp_panic_for_u64);
nonzero_check_clamp_panic!(core::num::NonZeroU128, nonzero_check_clamp_panic_for_u128);
nonzero_check_clamp_panic!(core::num::NonZeroUsize, nonzero_check_clamp_panic_for_usize);


macro_rules! nonzero_check_count_ones {
($nonzero_type:ty, $nonzero_check_count_ones_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_count_ones_for() {
let x: $nonzero_type = kani::any();
let result = x.count_ones();
// Since x is non-zero, count_ones should never return 0
assert!(result.get() > 0);
}
};
}

// Use the macro to generate different versions of the function for multiple types
nonzero_check_count_ones!(core::num::NonZeroI8, nonzero_check_count_ones_for_i8);
nonzero_check_count_ones!(core::num::NonZeroI16, nonzero_check_count_ones_for_i16);
nonzero_check_count_ones!(core::num::NonZeroI32, nonzero_check_count_ones_for_i32);
nonzero_check_count_ones!(core::num::NonZeroI64, nonzero_check_count_ones_for_i64);
nonzero_check_count_ones!(core::num::NonZeroI128, nonzero_check_count_ones_for_i128);
nonzero_check_count_ones!(core::num::NonZeroIsize, nonzero_check_count_ones_for_isize);
nonzero_check_count_ones!(core::num::NonZeroU8, nonzero_check_count_ones_for_u8);
nonzero_check_count_ones!(core::num::NonZeroU16, nonzero_check_count_ones_for_u16);
nonzero_check_count_ones!(core::num::NonZeroU32, nonzero_check_count_ones_for_u32);
nonzero_check_count_ones!(core::num::NonZeroU64, nonzero_check_count_ones_for_u64);
nonzero_check_count_ones!(core::num::NonZeroU128, nonzero_check_count_ones_for_u128);
nonzero_check_count_ones!(core::num::NonZeroUsize, nonzero_check_count_ones_for_usize);


macro_rules! nonzero_check_rotate_left_and_right {
($nonzero_type:ty, $nonzero_check_rotate_for:ident) => {
#[kani::proof]
pub fn $nonzero_check_rotate_for() {
let x: $nonzero_type = kani::any();
let n: u32 = kani::any();
let result = x.rotate_left(n).rotate_right(n);
assert!(result == x);
}
};
}

// Use the macro to generate different versions of the function for multiple types
nonzero_check_rotate_left_and_right!(core::num::NonZeroI8, nonzero_check_rotate_for_i8);
nonzero_check_rotate_left_and_right!(core::num::NonZeroI16, nonzero_check_rotate_for_i16);
nonzero_check_rotate_left_and_right!(core::num::NonZeroI32, nonzero_check_rotate_for_i32);
nonzero_check_rotate_left_and_right!(core::num::NonZeroI64, nonzero_check_rotate_for_i64);
nonzero_check_rotate_left_and_right!(core::num::NonZeroI128, nonzero_check_rotate_for_i128);
nonzero_check_rotate_left_and_right!(core::num::NonZeroIsize, nonzero_check_rotate_for_isize);
nonzero_check_rotate_left_and_right!(core::num::NonZeroU8, nonzero_check_rotate_for_u8);
nonzero_check_rotate_left_and_right!(core::num::NonZeroU16, nonzero_check_rotate_for_u16);
nonzero_check_rotate_left_and_right!(core::num::NonZeroU32, nonzero_check_rotate_for_u32);
nonzero_check_rotate_left_and_right!(core::num::NonZeroU64, nonzero_check_rotate_for_u64);
nonzero_check_rotate_left_and_right!(core::num::NonZeroU128, nonzero_check_rotate_for_u128);
nonzero_check_rotate_left_and_right!(core::num::NonZeroUsize, nonzero_check_rotate_for_usize);
}

0 comments on commit 367d8ff

Please sign in to comment.