Skip to content
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

Proofs for Vec::swap_remove, Option::as_slice, and VecDeque::swap #212

Merged
merged 64 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
9a8993d
added common codes for all proof of contracts
xsxszab Oct 7, 2024
55950bb
implemented integer type proof for contract for fn add, sub and offset
xsxszab Oct 7, 2024
ce13e8f
Merge branch 'main' into verify/ptr_mut
stogaru Oct 9, 2024
3682858
Adds proofs for tuple types
stogaru Oct 9, 2024
a6d4d62
Renames harnesses
stogaru Oct 9, 2024
dec8c30
Added unit type proofs for mut ptr
MayureshJoshi25 Oct 9, 2024
2be7639
Merge pull request #8 from stogaru/verify/ptr_mut_unit_types
stogaru Oct 11, 2024
75179dc
Merge branch 'verify/ptr_mut' into verify/ptr_mut_integer_types
xsxszab Oct 11, 2024
34c670e
Merge pull request #6 from stogaru/verify/ptr_mut_integer_types
xsxszab Oct 11, 2024
66c956e
Merge branch 'verify/ptr_mut' into verify/ptr_mut_composite
stogaru Oct 11, 2024
d9b8c65
Merge pull request #7 from stogaru/verify/ptr_mut_composite
stogaru Oct 11, 2024
0faac46
Combined macros
stogaru Oct 11, 2024
82345de
Fixes a typo
stogaru Oct 12, 2024
656209b
Removes an unnecessary attribute
stogaru Oct 12, 2024
46e839c
Merge pull request #9 from stogaru/verify/ptr_mut_combined
stogaru Oct 12, 2024
96a8a2e
refactored function contracts for add, sub and offset using the same_…
xsxszab Oct 23, 2024
852e96f
merged macros for add, sub and offset
xsxszab Oct 23, 2024
04bd61e
updated function contracts and proof for contracts for add(), sub() a…
xsxszab Oct 24, 2024
7557fc5
added support for unit type pointers
xsxszab Oct 31, 2024
76b2311
updated function contracts, removed unnecessary kani::assmue
xsxszab Nov 6, 2024
cb6a177
added comments to function contracts
xsxszab Nov 6, 2024
6385d4a
Merge pull request #12 from stogaru/verify/ptr_mut_refactor_harness
xsxszab Nov 7, 2024
a079a7a
added comments for magic numbers
xsxszab Nov 7, 2024
214f84d
Merge branch 'main' into verify/ptr_mut
stogaru Nov 7, 2024
51ded41
updated proofs using pointer generator
xsxszab Nov 15, 2024
fb6215e
fixed typos in comments
xsxszab Nov 15, 2024
f229fd9
rustfmt formatting
xsxszab Nov 15, 2024
20fffa3
reverse unnecessary rustfmt formatting
xsxszab Nov 15, 2024
b9054a8
temporary disabled check_mut_add_u8 test
xsxszab Nov 16, 2024
b528b0e
Clarified preconditions with additional notes
xsxszab Nov 27, 2024
9b90b23
added tracking issue info for the pointer generator bug
xsxszab Nov 27, 2024
b3b0620
Merge branch 'main' into verify/ptr_mut
tautschnig Nov 27, 2024
6dc7db5
Proof for VecDeque swap
stogaru Nov 29, 2024
46648ac
Corrects a bug in the proof.
stogaru Nov 30, 2024
afe1b16
Add proof for String:remove
szlee118 Dec 2, 2024
80b3f91
Use any_array at creation
szlee118 Dec 3, 2024
6e97438
align mut_ptr with usage_proofs branch
szlee118 Dec 5, 2024
f581759
Copied file from usage_proofs to verify/string_remove
szlee118 Dec 5, 2024
5de632a
Merge branch 'usage_proofs' into verify/string_remove
szlee118 Dec 5, 2024
081474e
Fix of any_where usage, hardcode constant
szlee118 Dec 5, 2024
9563408
Add a newline at the end of the file
stogaru Dec 6, 2024
51e903d
Add extra assertion and remove redundant assume
szlee118 Dec 6, 2024
8ec384e
Add description
szlee118 Dec 6, 2024
ee06313
Remove redundant white line
szlee118 Dec 6, 2024
160d9d7
Added proof for vec::swap_remove
MayureshJoshi25 Dec 6, 2024
5082a92
Update mod.rs
stogaru Dec 6, 2024
f552676
Merge pull request #22 from stogaru/verify/string_remove
stogaru Dec 6, 2024
41c3927
Merge pull request #24 from stogaru/verify/vecdeque_swap
stogaru Dec 6, 2024
b42123d
Merge pull request #25 from stogaru/verify/vec_swap_remove_usage_v2
stogaru Dec 6, 2024
1851037
Adds a proof for Option::as_slice
stogaru Dec 6, 2024
b9d950c
Merge branch 'main' into usage_proofs
stogaru Dec 6, 2024
e784b5e
Updates challenge 3
stogaru Dec 8, 2024
e9ca2e8
Merge branch 'main' into usage_proofs
stogaru Dec 8, 2024
67d4965
Merge branch 'main' into usage_proofs
stogaru Dec 9, 2024
7089335
Merge branch 'main' into usage_proofs
szlee118 Dec 9, 2024
cab796a
Update library/alloc/src/string.rs
szlee118 Dec 10, 2024
6fc9d20
Merge branch 'main' into usage_proofs
szlee118 Dec 10, 2024
33ae4f4
Removes a comment
stogaru Dec 11, 2024
0c36fee
Symbolic checking for remaining elements
stogaru Dec 11, 2024
3405ee3
Update check_remove harness with description and change array size
szlee118 Dec 11, 2024
a07478d
Merge branch 'usage_proofs' of https://github.com/stogaru/verify-rust…
szlee118 Dec 11, 2024
c334c96
Merge branch 'main' into usage_proofs
szlee118 Dec 12, 2024
ed1e26e
Removes String remove harness
stogaru Dec 12, 2024
991a76b
Merge branch 'main' into usage_proofs
stogaru Dec 12, 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
5 changes: 3 additions & 2 deletions doc/src/challenges/0003-pointer-arithmentic.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Challenge 3: Verifying Raw Pointer Arithmetic Operations

- **Status:** Open
- **Status:** Resolved
- **Tracking Issue:** [#76](https://github.com/model-checking/verify-rust-std/issues/76)
- **Start date:** *2024/06/24*
- **End date:** *2025/04/10*
- **End date:** *2024/12/11*
- **Reward:** *N/A*
- **Contributors:** [Surya Togaru](https://github.com/stogaru), [Yifei Wang](https://github.com/xsxszab), [Szu-Yu Lee](https://github.com/szlee118), [Mayuresh Joshi](https://github.com/MayureshJoshi25)

-------------------

Expand Down
43 changes: 43 additions & 0 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ mod spec_from_iter;
#[cfg(test)]
mod tests;

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

/// A double-ended queue implemented with a growable ring buffer.
///
/// The "default" usage of this type as a queue is to use [`push_back`] to add to
Expand Down Expand Up @@ -3079,3 +3082,43 @@ impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
deq
}
}

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

#[kani::proof]
fn check_vecdeque_swap() {
// The array's length is set to an arbitrary value, which defines its size.
// In this case, implementing a dynamic array is not possible using any_array
// The more elements in the array the longer the veification time.
const ARRAY_LEN: usize = 40;
feliperodri marked this conversation as resolved.
Show resolved Hide resolved
let mut arr: [u32; ARRAY_LEN] = kani::Arbitrary::any_array();
let mut deque: VecDeque<u32> = VecDeque::from(arr);
let len = deque.len();

// Generate valid indices within bounds
let i = kani::any_where(|&x: &usize| x < len);
let j = kani::any_where(|&x: &usize| x < len);

// Capture the elements at i and j before the swap
let elem_i_before = deque[i];
let elem_j_before = deque[j];

// Perform the swap
deque.swap(i, j);

// Postcondition: Verify elements have swapped places
assert_eq!(deque[i], elem_j_before);
assert_eq!(deque[j], elem_i_before);

// Ensure other elements remain unchanged
let k = kani::any_where(|&x: &usize| x < len);
if k != i && k != j {
assert!(deque[k] == arr[k]);
}
}

}
53 changes: 53 additions & 0 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3217,3 +3217,56 @@ impl From<char> for String {
c.to_string()
}
}



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

#[kani::proof]
#[kani::unwind(9)] // Unwind up to 9 times
feliperodri marked this conversation as resolved.
Show resolved Hide resolved
/// This proof harness verifies the safety of the `String::remove`
///
/// The harness checks:
/// 1. The string length decreases by one after the `remove` operation.
/// 2. The removed character is valid ASCII.
feliperodri marked this conversation as resolved.
Show resolved Hide resolved
/// 3. The removed character matches the character at the specified index in the original string.
///
/// This ensures the `remove` function behaves as expected for constrained inputs.
feliperodri marked this conversation as resolved.
Show resolved Hide resolved
fn check_remove() {
// array size is chosen because it is small enough to be feasible to check exhaustively
feliperodri marked this conversation as resolved.
Show resolved Hide resolved
const ARRAY_SIZE: usize = 8;
let arr: [u8; ARRAY_SIZE] = kani::Arbitrary::any_array();
for &byte in &arr {
kani::assume(byte.is_ascii()); // Constrain to ASCII characters
}

// Convert byte array to a String directly (safe since all are ASCII)
let mut s = unsafe { String::from_utf8_unchecked(arr.to_vec()) };
feliperodri marked this conversation as resolved.
Show resolved Hide resolved

// Ensure the string is not empty
kani::assume(!s.is_empty());

// Generate a valid index within the bounds of the string
let idx: usize = kani::any_where(|&x| x < s.len());

// Store the character at the index `idx` before calling `remove`
let original_char = s.chars().nth(idx).expect("Index out of bounds");

// Call the `remove` function
let removed_char = s.remove(idx);

// Verify the string length decreases correctly
assert_eq!(s.len(), arr.len() - 1);

// Verify the removed character is a valid ASCII character
assert!(removed_char.is_ascii());

// Assert that the removed character matches the original character at `idx`
assert_eq!(removed_char, original_char);
}
}

46 changes: 46 additions & 0 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4032,3 +4032,49 @@ impl<T, A: Allocator, const N: usize> TryFrom<Vec<T, A>> for [T; N] {
Ok(array)
}
}

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

// Size chosen for testing the empty vector (0), middle element removal (1)
// and last element removal (2) cases while keeping verification tractable
const ARRAY_LEN: usize = 3;

#[kani::proof]
pub fn verify_swap_remove() {

// Creating a vector directly from a fixed length arbitrary array
let mut arr: [i32; ARRAY_LEN] = kani::Arbitrary::any_array();
let mut vect = Vec::from(&arr);

// Recording the original length and a copy of the vector for validation
let original_len = vect.len();
let original_vec = vect.clone();

// Generating a nondeterministic index which is guaranteed to be within bounds
let index: usize = kani::any_where(|x| *x < original_len);

let removed = vect.swap_remove(index);

// Verifying that the length of the vector decreases by one after the operation is performed
assert!(vect.len() == original_len - 1, "Length should decrease by 1");

// Verifying that the removed element matches the original element at the index
assert!(removed == original_vec[index], "Removed element should match original");

// Verifying that the removed index now contains the element originally at the vector's last index if applicable
if index < original_len - 1 {
assert!(vect[index] == original_vec[original_len - 1], "Index should contain last element");
}

// Check that all other unaffected elements remain unchanged
let k = kani::any_where(|&x: &usize| x < original_len - 1);
if k != index {
assert!(vect[k] == arr[k]);
}

}
}
27 changes: 27 additions & 0 deletions library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2572,3 +2572,30 @@ impl<T, const N: usize> [Option<T>; N] {
self.try_map(core::convert::identity)
}
}

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

#[kani::proof]
fn verify_as_slice() {
if kani::any() {
// Case 1: Option is Some
let value: u32 = kani::any();
let some_option: Option<u32> = Some(value);

let slice = some_option.as_slice();
assert_eq!(slice.len(), 1); // The slice should have exactly one element
assert_eq!(slice[0], value); // The value in the slice should match
} else {
// Case 2: Option is None
let none_option: Option<u32> = None;

let empty_slice = none_option.as_slice();
assert_eq!(empty_slice.len(), 0); // The slice should be empty
assert!(empty_slice.is_empty()); // Explicit check for emptiness
}
}
}
Loading