-
Notifications
You must be signed in to change notification settings - Fork 97
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
Audit copy_nonoverlapping
intrinsic
#1201
Merged
adpaco-aws
merged 7 commits into
model-checking:main
from
adpaco-aws:audit-copy-nonoverlap
May 20, 2022
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
c25e445
Add new tests and split old ones
adpaco-aws 03d7f54
Handle `CopyNonOverlapping` statements from intrinsics code
adpaco-aws 26e8b33
Add missed changes on one test
adpaco-aws 8e4e0f1
Rename and add comments in `codegen_copy`
adpaco-aws ee200b1
Slight rewording for alignment checks
adpaco-aws 67ffffb
Fix format + suggestion
adpaco-aws a0a4a31
Merge branch 'main' into audit-copy-nonoverlap
adpaco-aws File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
2 changes: 2 additions & 0 deletions
2
tests/expected/intrinsics/copy-nonoverlapping/copy-overflow/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,2 @@ | ||
FAILURE\ | ||
copy_nonoverlapping: attempt to compute number in bytes which would overflow |
18 changes: 18 additions & 0 deletions
18
tests/expected/intrinsics/copy-nonoverlapping/copy-overflow/main.rs
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,18 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Checks that `copy_nonoverlapping` triggers an overflow failure if the `count` | ||
// argument can overflow a `usize` | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_unaligned() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
// Passing `max_count` is guaranteed to overflow | ||
// the count in bytes for `i32` pointers | ||
let max_count = usize::MAX / 4 + 1; | ||
|
||
unsafe { | ||
let dst = src.add(1) as *mut i32; | ||
core::intrinsics::copy_nonoverlapping(src, dst, max_count); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
tests/expected/intrinsics/copy-nonoverlapping/copy-overlapping/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 @@ | ||
memcpy src/dst overlap | ||
16 changes: 16 additions & 0 deletions
16
tests/expected/intrinsics/copy-nonoverlapping/copy-overlapping/main.rs
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,16 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Check that `copy_nonoverlapping` fails if the `src`/`dst` regions overlap. | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_with_overlap() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
|
||
unsafe { | ||
// The call to `copy_nonoverlapping` is expected to fail because | ||
// the `src` region and the `dst` region overlap in `arr[1]` | ||
let dst = src.add(1) as *mut i32; | ||
core::intrinsics::copy_nonoverlapping(src, dst, 2); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
tests/expected/intrinsics/copy-nonoverlapping/copy-unaligned-dst/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,2 @@ | ||
FAILURE\ | ||
`dst` must be properly aligned |
16 changes: 16 additions & 0 deletions
16
tests/expected/intrinsics/copy-nonoverlapping/copy-unaligned-dst/main.rs
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,16 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Checks that `copy_nonoverlapping` fails when `dst` is not aligned. | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_unaligned() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
|
||
unsafe { | ||
// Get an unaligned pointer with a single-byte offset | ||
let dst_i8: *const i8 = src.add(1) as *mut i8; | ||
let dst_unaligned = unsafe { dst_i8.add(1) as *mut i32 }; | ||
core::intrinsics::copy_nonoverlapping(src, dst_unaligned, 1); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
tests/expected/intrinsics/copy-nonoverlapping/copy-unaligned-src/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,2 @@ | ||
FAILURE\ | ||
`src` must be properly aligned |
17 changes: 17 additions & 0 deletions
17
tests/expected/intrinsics/copy-nonoverlapping/copy-unaligned-src/main.rs
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,17 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Checks that `copy_nonoverlapping` fails when `src` is not aligned. | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_unaligned() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
|
||
unsafe { | ||
// Get an unaligned pointer with a single-byte offset | ||
let src_i8: *const i8 = src as *const i8; | ||
let src_unaligned = unsafe { src_i8.add(1) as *const i32 }; | ||
let dst = src.add(1) as *mut i32; | ||
core::intrinsics::copy_nonoverlapping(src_unaligned, dst, 1); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
tests/expected/intrinsics/copy-nonoverlapping/copy-unreadable-src/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,2 @@ | ||
FAILURE\ | ||
memcpy source region readable |
16 changes: 16 additions & 0 deletions
16
tests/expected/intrinsics/copy-nonoverlapping/copy-unreadable-src/main.rs
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,16 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Checks that `copy_nonoverlapping` fails when `src` is not valid for reads. | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_invalid() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
|
||
unsafe { | ||
// Get an invalid pointer with a negative offset | ||
let src_invalid = unsafe { src.sub(1) as *const i32 }; | ||
let dst = src.add(1) as *mut i32; | ||
core::intrinsics::copy_nonoverlapping(src_invalid, dst, 1); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
tests/expected/intrinsics/copy-nonoverlapping/copy-unwritable-dst/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,2 @@ | ||
FAILURE\ | ||
memcpy destination region writeable |
15 changes: 15 additions & 0 deletions
15
tests/expected/intrinsics/copy-nonoverlapping/copy-unwritable-dst/main.rs
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,15 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Checks that `copy_nonoverlapping` fails when `dst` is not valid for writes. | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_invalid() { | ||
let arr: [i32; 3] = [0, 1, 0]; | ||
let src: *const i32 = arr.as_ptr(); | ||
|
||
unsafe { | ||
// Get an invalid pointer with an out-of-bounds offset | ||
let dst_invalid = src.add(3) as *mut i32; | ||
core::intrinsics::copy_nonoverlapping(src, dst_invalid, 1); | ||
} | ||
} |
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 |
---|---|---|
@@ -1,2 +1,2 @@ | ||
FAILURE\ | ||
`dst` is properly aligned | ||
`dst` must be properly aligned |
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 |
---|---|---|
@@ -1,2 +1,2 @@ | ||
FAILURE\ | ||
`src` is properly aligned | ||
`src` must be properly aligned |
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 |
---|---|---|
@@ -1,2 +1,2 @@ | ||
FAILURE\ | ||
`dst` is properly aligned | ||
`dst` must be properly aligned |
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 |
---|---|---|
@@ -1,84 +1,18 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
#![feature(core_intrinsics)] | ||
/// kani main.rs -- --default-unwind 20 --unwinding-assertions | ||
use std::mem; | ||
use std::ptr; | ||
|
||
// Note: Calls to `copy_nonoverlapping` are handled by `codegen_statement` | ||
// and not `codegen_intrinsic`: https://github.com/model-checking/kani/issues/1198 | ||
// Check that `copy_nonoverlapping` works as expected: Copies a number `n` of elements from | ||
// pointer `src` to pointer `dst`. Their regions of memory do not overlap, otherwise the | ||
// call to `copy_nonoverlapping` would fail (a separate test checks for this). | ||
|
||
/// https://doc.rust-lang.org/std/ptr/fn.copy_nonoverlapping.html | ||
/// Moves all the elements of `src` into `dst`, leaving `src` empty. | ||
fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) { | ||
let src_len = src.len(); | ||
let dst_len = dst.len(); | ||
|
||
// Ensure that `dst` has enough capacity to hold all of `src`. | ||
dst.reserve(src_len); | ||
|
||
unsafe { | ||
// The call to offset is always safe because `Vec` will never | ||
// allocate more than `isize::MAX` bytes. | ||
let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); | ||
let src_ptr = src.as_ptr(); | ||
|
||
// Truncate `src` without dropping its contents. We do this first, | ||
// to avoid problems in case something further down panics. | ||
src.set_len(0); | ||
|
||
// The two regions cannot overlap because mutable references do | ||
// not alias, and two different vectors cannot own the same | ||
// memory. | ||
ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); | ||
|
||
// Notify `dst` that it now holds the contents of `src`. | ||
dst.set_len(dst_len + src_len); | ||
} | ||
} | ||
|
||
fn test_append() { | ||
let mut a = vec!['r']; | ||
let mut b = vec!['u', 's', 't']; | ||
|
||
append(&mut a, &mut b); | ||
|
||
assert!(a == &['r', 'u', 's', 't']); | ||
assert!(b.is_empty()); | ||
} | ||
|
||
/// Test the swap example from https://doc.redox-os.org/std/std/intrinsics/fn.copy_nonoverlapping.html | ||
/// Using T as uninitialized as in the example gives other errors, which we will solve later. | ||
/// For this test, passing in a default value that gets overridden is sufficient. | ||
fn swap_with_default<T>(x: &mut T, y: &mut T, default: T) { | ||
#[kani::proof] | ||
fn test_copy_nonoverlapping_simple() { | ||
let mut expected_val = 42; | ||
let src: *mut i32 = &mut expected_val as *mut i32; | ||
let mut old_val = 99; | ||
let dst: *mut i32 = &mut old_val; | ||
unsafe { | ||
// Give ourselves some scratch space to work with | ||
// let mut t: T = mem::uninitialized(); | ||
let mut t: T = default; | ||
|
||
// Perform the swap, `&mut` pointers never alias | ||
ptr::copy_nonoverlapping(x, &mut t, 1); | ||
ptr::copy_nonoverlapping(y, x, 1); | ||
ptr::copy_nonoverlapping(&t, y, 1); | ||
|
||
// y and t now point to the same thing, but we need to completely forget `tmp` | ||
// because it's no longer relevant. | ||
mem::forget(t); | ||
core::intrinsics::copy_nonoverlapping(src, dst, 1); | ||
assert!(*dst == expected_val); | ||
} | ||
} | ||
|
||
/// another test for copy_nonoverlapping, from | ||
/// https://doc.redox-os.org/std/std/intrinsics/fn.copy_nonoverlapping.html | ||
fn test_swap() { | ||
let mut x = 12; | ||
let mut y = 13; | ||
swap_with_default(&mut x, &mut y, 3); | ||
assert!(x == 13); | ||
assert!(y == 12); | ||
} | ||
|
||
#[kani::proof] | ||
fn main() { | ||
test_swap(); | ||
test_append(); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Is this a CBMC message? I was wondering if we change it to say copy_nonoverlap here. Do we use memcpy anywhere else?
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.
Yes, this is a CBMC message so there's not much we can do. We use
memcpy
in our__rust_realloc
C implementation but we don't generate calls tomemcpy
anywhere else.