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

Checking memory initialization in presence of copy and copy_nonoverlapping produces false positives #3347

Closed
artemagvanian opened this issue Jul 16, 2024 · 0 comments · Fixed by #3350
Assignees
Labels
[C] Bug This is a bug. Something isn't working. [F] Spurious Failure Issues that cause Kani verification to fail despite the code being correct.

Comments

@artemagvanian
Copy link
Contributor

Trying to verify the following code with memory initialization checks enabled (-Z uninit-checks):

#[derive(kani::Arbitrary)]
struct S(u32, u8);

#[kani::proof]
unsafe fn main() {
    let mut a: S = kani::any();
    let b: S = kani::any();
    let a_ptr = &mut a as *mut S;
    std::ptr::write_unaligned(a_ptr, b);
}

yield the following error:

Failed Checks: Undefined Behavior: Reading from an uninitialized pointer of type `*const u8`
 File: ".../.rustup/toolchains/nightly-2024-07-15-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/intrinsics.rs", line 2958, in std::intrinsics::copy_nonoverlapping::<u8>

with Kani version: 0.53.0

I expected to see this happen:

VERIFICATION:- SUCCESSFUL

According to the Rust documentaiton, both copy and copy_nonoverlapping are untyped:

The copy is “untyped” in the sense that data may be uninitialized or otherwise violate the requirements of T. The initialization state is preserved exactly.

However, Kani treats a copy as a read followed by a write, which triggers memory initialization checks while it shouldn't. This becomes evident since the source code of write_unaligned copies the data byte-by-byte.

pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
    // SAFETY: the caller must guarantee that `dst` is valid for writes.
    // `dst` cannot overlap `src` because the caller has mutable access
    // to `dst` while `src` is owned by this function.
    unsafe {
        copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::<T>());
        // We are calling the intrinsic directly to avoid function calls in the generated code.
        intrinsics::forget(src);
    }
}
@artemagvanian artemagvanian added [C] Bug This is a bug. Something isn't working. [F] Spurious Failure Issues that cause Kani verification to fail despite the code being correct. labels Jul 16, 2024
@artemagvanian artemagvanian self-assigned this Jul 16, 2024
github-merge-queue bot pushed a commit that referenced this issue Aug 15, 2024
This PR adds support of copying memory initialization state without
checks in-between. Every time a copy is performed, the tracked byte is
non-deterministically switched.

Resolves #3347

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C] Bug This is a bug. Something isn't working. [F] Spurious Failure Issues that cause Kani verification to fail despite the code being correct.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant