-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add experimental API to generate arbitrary pointers (#3538)
This change adds a pointer generator that can non-deterministically generate a pointer with different properties. This generator allows users to build pointers with different allocation status, initialization and alignment. It contains an internal buffer that it uses to generate `InBounds` and `OutOfBounds` pointers. In those cases, the pointers will have the same provenance as the generator, and the same lifetime. This approach is different than generating a pointer from an arbitrary `usize`. Kani uses demonic non-determinism to track allocation lifetimes, which makes hard to reason about during verification. I.e., one cannot assume a pointer is valid, and initialized, and this can only be accomplished by manually tracking the pointer status. I added the new API under `-Z mem-predicates` since it allows reasoning about memory, and I was hoping this wouldn't need another unstable flag. :smile: 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: Zyad Hassan <88045115+zhassan-aws@users.noreply.github.com>
- Loading branch information
1 parent
f3ed5e8
commit d2f5dbe
Showing
14 changed files
with
743 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
Checking harness check_arbitrary_ptr... | ||
|
||
Status: SUCCESS\ | ||
Description: ""OutOfBounds"" | ||
|
||
Status: SUCCESS\ | ||
Description: ""InBounds"" | ||
|
||
Status: SUCCESS\ | ||
Description: ""NullPtr"" | ||
|
||
Status: FAILURE\ | ||
Description: ""DeadObject"" | ||
|
||
Status: SATISFIED\ | ||
Description: "Dangling" | ||
|
||
Status: UNREACHABLE\ | ||
Description: ""Dangling write"" | ||
|
||
Verification failed for - check_arbitrary_ptr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// | ||
// kani-flags: -Z mem-predicates | ||
//! Check the behavior of the new `PointerGenerator`. | ||
extern crate kani; | ||
|
||
use kani::{AllocationStatus, PointerGenerator, cover}; | ||
|
||
/// Harness that checks that all cases are covered and the code behaves as expected. | ||
/// | ||
/// Note that for `DeadObject`, `Dangling`, and `OutOfBounds` the predicate will fail due to demonic non-determinism. | ||
#[kani::proof] | ||
fn check_arbitrary_ptr() { | ||
let mut generator = PointerGenerator::<10>::new(); | ||
let arbitrary = generator.any_alloc_status::<char>(); | ||
let ptr = arbitrary.ptr; | ||
match arbitrary.status { | ||
AllocationStatus::Dangling => { | ||
cover!(true, "Dangling"); | ||
assert!(!kani::mem::can_write_unaligned(ptr), "Dangling write"); | ||
} | ||
AllocationStatus::Null => { | ||
assert!(!kani::mem::can_write_unaligned(ptr), "NullPtr"); | ||
} | ||
AllocationStatus::DeadObject => { | ||
// Due to demonic non-determinism, the API will trigger an error. | ||
assert!(!kani::mem::can_write_unaligned(ptr), "DeadObject"); | ||
} | ||
AllocationStatus::OutOfBounds => { | ||
assert!(!kani::mem::can_write_unaligned(ptr), "OutOfBounds"); | ||
} | ||
AllocationStatus::InBounds => { | ||
// This should always succeed | ||
assert!(kani::mem::can_write_unaligned(ptr), "InBounds"); | ||
} | ||
}; | ||
} |
9 changes: 9 additions & 0 deletions
9
tests/expected/arbitrary/ptrs/pointer_generator_error.expected
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
error[E0080]: evaluation of `kani::PointerGenerator::<0>::VALID` failed\ | ||
|
||
the evaluated program panicked at 'PointerGenerator requires at least one byte.' | ||
|
||
note: the above error was encountered while instantiating `fn kani::PointerGenerator::<0>::new`\ | ||
pointer_generator_error.rs\ | ||
|\ | ||
| let _generator = PointerGenerator::<0>::new();\ | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// | ||
// kani-flags: -Z mem-predicates | ||
//! Check misusage of pointer generator fails compilation. | ||
extern crate kani; | ||
|
||
use kani::PointerGenerator; | ||
|
||
pub fn check_invalid_generator() { | ||
let _generator = PointerGenerator::<0>::new(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
Checking harness check_overlap... | ||
|
||
Status: SATISFIED\ | ||
Description: "Same" | ||
|
||
Status: SATISFIED\ | ||
Description: "Overlap" | ||
|
||
Status: SATISFIED\ | ||
Description: "Greater" | ||
|
||
Status: SATISFIED\ | ||
Description: "Smaller" | ||
|
||
Checking harness check_alignment... | ||
|
||
Status: SUCCESS\ | ||
Description: ""Aligned"" | ||
|
||
Status: SUCCESS\ | ||
Description: ""Unaligned"" | ||
|
||
Checking harness check_inbounds_initialized... | ||
|
||
Status: SUCCESS\ | ||
Description: ""ValidRead"" | ||
|
||
Checking harness check_inbounds... | ||
|
||
Status: SATISFIED\ | ||
Description: "Uninitialized" | ||
|
||
Status: SATISFIED\ | ||
Description: "Initialized" | ||
|
||
Status: SUCCESS\ | ||
Description: ""ValidWrite"" | ||
|
||
Complete - 4 successfully verified harnesses, 0 failures, 4 total. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// | ||
// kani-flags: -Z mem-predicates | ||
//! Check different cases for `PointerGenerator` for in-bounds pointers. | ||
//! TODO: Enable initialization checks (`-Z uninit-checks`) once we add support to unions. | ||
//! The current instrumentation does not work in the presence of MaybeUninit which we use | ||
//! to implement PointerGenerator. | ||
//! Kani will detect the usage of MaybeUninit and fail the verification. | ||
extern crate kani; | ||
|
||
use kani::PointerGenerator; | ||
|
||
#[kani::proof] | ||
fn check_inbounds() { | ||
let mut generator = kani::pointer_generator::<char, 3>(); | ||
let ptr = generator.any_in_bounds::<char>().ptr; | ||
kani::cover!(!kani::mem::can_read_unaligned(ptr), "Uninitialized"); | ||
kani::cover!(kani::mem::can_read_unaligned(ptr), "Initialized"); | ||
assert!(kani::mem::can_write_unaligned(ptr), "ValidWrite"); | ||
} | ||
|
||
#[kani::proof] | ||
fn check_inbounds_initialized() { | ||
let mut generator = kani::pointer_generator::<char, 3>(); | ||
let arbitrary = generator.any_in_bounds::<char>(); | ||
kani::assume(arbitrary.is_initialized); | ||
assert!(kani::mem::can_read_unaligned(arbitrary.ptr), "ValidRead"); | ||
} | ||
|
||
#[kani::proof] | ||
fn check_alignment() { | ||
let mut generator = kani::pointer_generator::<char, 2>(); | ||
let ptr: *mut char = generator.any_in_bounds().ptr; | ||
if ptr.is_aligned() { | ||
assert!(kani::mem::can_write(ptr), "Aligned"); | ||
} else { | ||
assert!(!kani::mem::can_write(ptr), "Not aligned"); | ||
assert!(kani::mem::can_write_unaligned(ptr), "Unaligned"); | ||
} | ||
} | ||
|
||
#[kani::proof] | ||
fn check_overlap() { | ||
let mut generator = kani::pointer_generator::<u16, 5>(); | ||
let ptr_1 = generator.any_in_bounds::<u16>().ptr; | ||
let ptr_2 = generator.any_in_bounds::<u16>().ptr; | ||
kani::cover!(ptr_1 == ptr_2, "Same"); | ||
kani::cover!(ptr_1 == unsafe { ptr_2.byte_add(1) }, "Overlap"); | ||
|
||
let distance = unsafe { ptr_1.offset_from(ptr_2) }; | ||
kani::cover!(distance > 0, "Greater"); | ||
kani::cover!(distance < 0, "Smaller"); | ||
|
||
assert!(distance >= -4 && distance <= 4, "Expected a maximum distance of 4 elements"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.