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

Contracts: Can't include non-Copy types in contract #3027

Open
adpaco-aws opened this issue Feb 13, 2024 · 4 comments
Open

Contracts: Can't include non-Copy types in contract #3027

adpaco-aws opened this issue Feb 13, 2024 · 4 comments
Assignees
Labels
[C] Bug This is a bug. Something isn't working. [F] Crash Kani crashed

Comments

@adpaco-aws
Copy link
Contributor

When trying out the contracts feature (from Kani 0.46.0) in one of my projects, I got the following errors:

error[E0507]: cannot move out of `*e_renamed` which is behind a shared reference
  --> src/lib.rs:79:5
   |
79 |     #[kani::ensures(match result { Ok(t) => Self::typecheck_2(*e, t), Err(_) => true})]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `*e_renamed` has type `Expr`, which does not implement the `Copy` trait
   |
   = note: this error originates in the attribute macro `kani::ensures` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0507]: cannot move out of `*e_renamed` which is behind a shared reference
  --> src/lib.rs:79:5
   |
79 |     #[kani::ensures(match result { Ok(t) => Self::typecheck_2(*e, t), Err(_) => true})]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `*e_renamed` has type `Expr`, which does not implement the `Copy` trait
   |
   = note: this error originates in the attribute macro `kani::ensures` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0507`.
error: could not compile `interpreter` (lib) due to 3 previous errors
error: Failed to execute cargo (exit status: 101). Found 3 compilation errors.

I've opened #3026 for improving the error message, but anyway it's clear to me that it's asking for Expr to implement Copy. In my case, Expr is an enum defined as follows:

pub enum Expr {
    Int(i32),
    Bool(bool),
    If {
        test_expr: Box<Expr>,
        then_expr: Box<Expr>,
        else_expr: Box<Expr>,
    },
    BinaryApp {
        op: BinaryOp,
        arg1: Box<Expr>,
        arg2: Box<Expr>,
    },
}

Here, the usage of Box<...> prevents me from directly deriving the Copy trait. As far as I know, the Copy trait cannot be implemented for Box<...> because we'd end up with multiple boxes referencing the same value.

Can you recommend a good workaround for this? I think it should be possible to have a custom impl for Copy that behaves like Clone, but then I'm not sure it'd work with the contracts implementation (and I'd expect performance issues even if it did).

If you'd like to reproduce the error or anything else, the complete program can be found in the kani-contracts branch of my project. Once it's cloned, simply run cargo kani.

@adpaco-aws adpaco-aws added the [C] Bug This is a bug. Something isn't working. label Feb 13, 2024
@JustusAdam
Copy link
Contributor

JustusAdam commented Feb 13, 2024

Yes, this makes sense. Why does typecheck_2 take e by value and not by reference? I think that would fix your problem.

The problem is not that contracts in general need Copy, but typecheck_2 which you're calling in the contract takes e by value and thus requires Copy.

@JustusAdam
Copy link
Contributor

But also I think we could probably avoid actually renaming e to e_renamed and instead rely on macro hygiene to distinguish the two. That would improve the error message.

@adpaco-aws
Copy link
Contributor Author

The problem is not that contracts in general need Copy, but typecheck_2 which you're calling in the contract takes e by value and thus requires Copy.

Oh, I see. Then let me check if I can pass a reference instead. Thank you!

@adpaco-aws
Copy link
Contributor Author

If I pass the argument by reference then rustc crashes:

thread 'rustc' has overflowed its stack
fatal runtime error: stack overflow
error: could not compile `interpreter` (lib); 2 warnings emitted

Caused by:
  process didn't exit successfully: `/Users/adrian/.kani/kani-0.46.0/bin/kani-compiler --crate-name interpreter --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=99 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked -Cllvm-args=--reachability=harnesses -C metadata=1a58319f898c6d22 -C extra-filename=-1a58319f898c6d22 --out-dir /Users/adrian/bolero-playground-clean/interpreter/target/kani/x86_64-apple-darwin/debug/deps --target x86_64-apple-darwin -C incremental=/Users/adrian/bolero-playground-clean/interpreter/target/kani/x86_64-apple-darwin/debug/incremental -L dependency=/Users/adrian/bolero-playground-clean/interpreter/target/kani/x86_64-apple-darwin/debug/deps -L dependency=/Users/adrian/bolero-playground-clean/interpreter/target/kani/debug/deps --extern bolero=/Users/adrian/bolero-playground-clean/interpreter/target/kani/x86_64-apple-darwin/debug/deps/libbolero-64e9f6a7f1410dbc.rmeta --extern bolero_generator=/Users/adrian/bolero-playground-clean/interpreter/target/kani/x86_64-apple-darwin/debug/deps/libbolero_generator-d989fabb5284594b.rmeta -C overflow-checks=on -Z unstable-options -Z trim-diagnostic-paths=no -Z human_readable_cgu_names -Z always-encode-mir --cfg=kani -Z 'crate-attr=feature(register_tool)' -Z 'crate-attr=register_tool(kanitool)' --sysroot /Users/adrian/.kani/kani-0.46.0 -L /Users/adrian/.kani/kani-0.46.0/lib --extern kani --extern 'noprelude:std=/Users/adrian/.kani/kani-0.46.0/lib/libstd.rlib' -C panic=abort -C symbol-mangling-version=v0 -Z panic_abort_tests=yes --kani-compiler '-Cllvm-args=--check-version=0.46.0 --log-level=warn --assertion-reach-checks --goto-c'` (signal: 6, SIGABRT: process abort signal)
error: Failed to execute cargo (exit status: 101). Found 0 compilation errors.

I've pushed the commit to the branch kani-contracts-crash.

@adpaco-aws adpaco-aws added the [F] Crash Kani crashed label Feb 14, 2024
@feliperodri feliperodri self-assigned this Feb 28, 2024
@feliperodri feliperodri added this to the Function Contracts MVP milestone Jun 6, 2024
pi314mm added a commit that referenced this issue Jun 19, 2024
The current method for creating the modifies wrapper requires changing
the `ensures` clause to have `_renamed` variables which are unsafe
copies of the original function arguments. This causes issues with
regards to some possible tests as in #3239.

This change removes the `_renamed` variables and instead simply changes
the modifies clauses within the replace to unsafely dereference the
pointer to modify the contents of it unsafely, condensing all instances
of unsafe Rust into a single location.

Resolves #3239
Resolves #3026
May affect #3027. In my attempt to run this example with slight
modification to fit the current implementation, I got the error `CBMC
appears to have run out of memory. You may want to rerun your proof in
an environment with additional memory or use stubbing to reduce the size
of the code the verifier reasons about.` This suggests that the
compilation is working appropriately but the test case is just too large
for CBMC.

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: Matias Scharager <mscharag@amazon.com>
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] Crash Kani crashed
Projects
None yet
Development

No branches or pull requests

3 participants