├── .dockerignore
├── .github
└── workflows
│ └── rust.yaml
├── .gitignore
├── AUTHORS
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── cargo-verify
├── Cargo.toml
├── rustfmt.toml
└── src
│ ├── backends_common.rs
│ ├── klee.rs
│ ├── main.rs
│ ├── proptest.rs
│ ├── run_tools.rs
│ ├── seahorn.rs
│ ├── smack.rs
│ └── utils.rs
├── compatibility-test
├── .gitignore
├── Cargo.toml
└── src
│ ├── collections.rs
│ ├── compose.rs
│ ├── dynamic.rs
│ ├── enumeration.rs
│ ├── main.rs
│ └── shouldfail.rs
├── demos
├── README.md
├── bottlenecks
│ ├── bornholt2018-1
│ │ ├── Cargo.toml
│ │ └── src
│ │ │ └── main.rs
│ ├── merging
│ │ ├── Cargo.toml
│ │ └── src
│ │ │ └── main.rs
│ └── regex
│ │ ├── Cargo.toml
│ │ └── src
│ │ └── main.rs
└── simple
│ ├── annotations
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── src
│ │ └── main.rs
│ └── verify.sh
│ ├── argv
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
│ ├── errors
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── src
│ │ └── main.rs
│ └── verify.sh
│ ├── ffi
│ ├── Cargo.toml
│ ├── bar.c
│ ├── build.rs
│ └── src
│ │ └── main.rs
│ ├── klee
│ ├── Cargo.toml
│ ├── src
│ │ └── main.rs
│ └── verify.sh
│ ├── seahorn
│ ├── Cargo.toml
│ ├── src
│ │ └── main.rs
│ └── verify.sh
│ ├── string
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
│ └── vectest
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── docker
├── README.md
├── base
│ └── Dockerfile
├── build
├── init
├── klee
│ ├── Dockerfile
│ ├── build_googletest
│ └── build_klee
├── mkimage
├── run
├── rust2calltree
│ └── Dockerfile
├── rvt
│ └── Dockerfile
├── seahorn
│ └── Dockerfile
├── smack
│ └── Dockerfile
├── solvers
│ └── Dockerfile
└── sudo_if_needed.bash
├── docs
├── .gitignore
├── Gemfile
├── Gemfile.lock
├── _config.yml
├── _internal
│ └── howto-blog.md
├── _posts
│ ├── 2020-09-01-using-klee.md
│ ├── 2020-09-02-using-annotations.md
│ ├── 2020-09-03-using-propverify.md
│ ├── 2020-09-07-install-crux.md
│ ├── 2020-09-09-using-argv.md
│ ├── 2020-12-11-using-ffi.md
│ ├── 2021-03-12-profiling-rust.md
│ ├── 2021-03-20-verifying-vectorized-code.md
│ ├── 2021-03-29-klee-status.md
│ ├── 2021-04-01-using-seahorn.md
│ ├── 2021-05-15-verifying-vectorized-code2.md
│ ├── 2021-05-19-fixing-bottlenecks.md
│ ├── 2021-07-14-coreutils.md
│ ├── 2021-08-15-rvt-risks.md
│ ├── 2021-08-22-rust-on-linux-1.md
│ ├── 2021-08-23-rust-on-linux-2.md
│ ├── 2021-08-24-rust-on-linux-3.md
│ └── 2021-09-01-retrospective.md
├── about.md
├── assets
│ └── main.scss
├── images
│ ├── Kangrejos.pdf
│ ├── profiling-regex.png
│ ├── retrospective-all.png
│ ├── retrospective-horizontal-50.png
│ ├── retrospective-shift-left.png
│ ├── retrospective-vertical-10.png
│ └── retrospective-vertical-50.png
├── index.md
├── tools.md
└── using-klee.md
├── propverify
├── AUTHORS
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ ├── lib.rs
│ └── strategy.rs
├── runtime
├── .gitignore
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE-APACHE
├── LICENSE-MIT
├── Makefile
├── README.md
└── src
│ ├── atexit.c
│ ├── memrchr.c
│ ├── posix_memalign.c
│ └── pthread.c
├── rust2calltree
├── Cargo.toml
└── src
│ └── main.rs
├── rvt-patch-llvm
├── Cargo.toml
└── src
│ └── main.rs
├── scripts
├── cargo-verify-seahorn.sh
├── old-cargo-verify
└── regression-test
├── simd_emulation
├── .gitignore
├── AUTHORS
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── Makefile
└── src
│ └── lib.rs
└── verification-annotations
├── AUTHORS
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── build.rs
├── lib
├── seahorn.c
└── smack-rust.c
└── src
├── lib.rs
├── tests.rs
├── traits.rs
└── verifier
├── crux.rs
├── klee.rs
├── mod.rs
├── seahorn.rs
└── smack.rs
/.dockerignore:
--------------------------------------------------------------------------------
1 | /.git
2 | /.github
3 | /bin
4 | /docs
5 |
6 | /compatibility-test
7 | /demos
8 | /docs
9 | /downloads
10 | /experiments
11 | /runtime/build_*
12 | /verification-annotations
13 |
14 | # .dockerignore files differ from .gitignore files in that
15 | # all filenames implicitly start at the root so we have
16 | # to replicate the following rules once for every level
17 | # of the directory hierarchy.
18 |
19 |
20 | *.bc
21 | *.ll
22 | *.o
23 | target
24 | kleeout*
25 | klee-out-*
26 | klee-last
27 |
28 | */*.bc
29 | */*.ll
30 | */*.o
31 | */target
32 | */kleeout*
33 | */klee-out-*
34 | */klee-last
35 |
36 | */*/*.bc
37 | */*/*.ll
38 | */*/*.o
39 | */*/target
40 | */*/kleeout*
41 | */*/klee-out-*
42 | */*/klee-last
43 |
44 | */*/*/*.bc
45 | */*/*/*.ll
46 | */*/*/*.o
47 | */*/*/target
48 | */*/*/kleeout*
49 | */*/*/klee-out-*
50 | */*/*/klee-last
51 |
--------------------------------------------------------------------------------
/.github/workflows/rust.yaml:
--------------------------------------------------------------------------------
1 | name: Rust
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 |
8 | jobs:
9 | format:
10 | name: Format
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Install correct nightly toolchain
14 | uses: actions-rs/toolchain@v1
15 | with:
16 | toolchain: nightly-2021-05-07
17 | override: true
18 | components: rustfmt
19 | - uses: actions/checkout@v2
20 | - name: Format Rust code
21 | run: git ls-files | grep 'rs$' | xargs rustfmt +nightly-2021-05-07 --check
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 | /downloads
3 | /experiments
4 | /runtime/build
5 |
6 | Cargo.lock
7 | target/
8 | kleeout/
9 | klee-out-*
10 | klee-last
11 | *.bc
12 | *.ll
13 | *.o
14 | .*un~
15 | .*swp
16 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of Rust verification tool's significant contributors.
2 | #
3 | # This does not necessarily list everyone who has contributed code,
4 | # especially since many employees of one corporation may be contributing.
5 | # To see the full list of contributors, see the revision history in
6 | # source control.
7 | Google LLC
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic
7 | Versioning](https://semver.org/spec/v2.0.0.html).
8 |
9 | ## [Unreleased]
10 |
11 | ### Added
12 |
13 | - Docker support.
14 |
15 | This is now the preferred way of setting up your system.
16 | Older installation instructions have been deleted.
17 |
18 | Thanks to Steven Jiang for this.
19 |
20 | - Demos directory.
21 |
22 | Demonstration code (typically the same code used in documentation)
23 | is now in the demos directory.
24 |
25 | - FFI support.
26 |
27 | This makes it possible to verify programs that combine
28 | C and Rust. See `demos/simple/ffi`.
29 |
30 | - `std::env::args()` support.
31 |
32 | This makes it possible to verify programs that have
33 | command line arguments. See `demos/simple/argv`.
34 |
35 | ### Changed
36 |
37 | ### Deprecated
38 |
39 | ### Removed
40 |
41 | ### Fixed
42 |
43 | - Many minor documentation errors
44 | - cargo-verify verbosity control produces more useful output for debugging
45 | cargo-verify with.
46 |
47 |
48 |
49 | [0.0.2]: https://github.com/project-oak/rust-verification-tools/compare/v0.0.1...v0.0.2
50 | [0.0.1]: https://github.com/project-oak/rust-verification-tools/releases/tag/v0.0.1
51 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement (CLA). You (or your employer) retain the copyright to your
10 | contribution; this simply gives us permission to use and redistribute your
11 | contributions as part of the project. Head over to
12 | to see your current agreements on file or
13 | to sign a new one.
14 |
15 | You generally only need to submit a CLA once, so if you've already submitted one
16 | (even if it was for a different project), you probably don't need to do it
17 | again.
18 |
19 | ## Code reviews
20 |
21 | All submissions, including submissions by project members, require review. We
22 | use GitHub pull requests for this purpose. Consult
23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
24 | information on using pull requests.
25 |
26 | ## Community Guidelines
27 |
28 | This project follows
29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
30 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2020 The Rust verification tools Authors.
2 | Based on parts of proptest which is Copyright 2017, 2018 Jason Lingle.
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rust verification tools
2 |
3 | This is a collection of tools/libraries to support both static
4 | and dynamic verification of Rust programs.
5 |
6 | We see static verification (formal verification) and dynamic verification
7 | (testing) as two parts of the same activity and so these tools can be used for
8 | either form of verification.
9 |
10 | - Dynamic verification using the
11 | [proptest](https://github.com/AltSysrq/proptest)
12 | fuzzing/property testing library.
13 |
14 | - Static verification using the
15 | [KLEE](http://klee.github.io/)
16 | symbolic execution engine.
17 |
18 | We aim to add other backends in the near future.
19 |
20 | In addition, [we document](https://project-oak.github.io/rust-verification-tools/about.html) how the tools we wrote work
21 | in case you are porting a verification tool for use with Rust.
22 | (In particular, we describe how to generate LLVM bitcode files that can
23 | be used with LLVM-based verification tools.)
24 |
25 | ## Tools and libraries
26 |
27 | - `verification-annotations` crate: an FFI layer for creating symbolic values in
28 | [KLEE](http://klee.github.io/)
29 |
30 | - `propverify` crate:
31 | an implementation of the [proptest](https://github.com/AltSysrq/proptest)
32 | library for use with static verification tools.
33 |
34 | - `cargo-verify`: a tool for compiling a crate and
35 | either verifying main/tests or for fuzzing main/tests.
36 | (Use the `--backend` flag to select which.)
37 |
38 | - `compatibility-test` test crate:
39 | test programs that can be verified either using the original `proptest`
40 | library or using `propverify`.
41 | Used to check that proptest and propverify are compatible with each other.
42 |
43 | ## Usage
44 |
45 | TL;DR
46 |
47 | 1. Install
48 | For installation with Docker, see the Usage section of [our main docs](https://project-oak.github.io/rust-verification-tools/about.html).
49 |
50 | 2. Fuzz some examples with proptest
51 |
52 | ```
53 | cd compatibility-test
54 | cargo test
55 | cd ..
56 | ```
57 |
58 | (You can also use
59 | `cargo-verify --backend=proptest --verbose`.)
60 |
61 | One test should fail – this is correct behaviour.
62 |
63 | 3. Verify some examples with propverify
64 |
65 | `cd verification-annotations; cargo-verify --tests`
66 |
67 | `cd verification-annotations; cargo-verify --tests`
68 |
69 | No tests should fail.
70 |
71 | 4. Read [the propverify intro](https://project-oak.github.io/rust-verification-tools/using-propverify/) for an example
72 | of fuzzing with `proptest` and verifying with `propverify`.
73 |
74 | 5. Read [the proptest book](https://altsysrq.github.io/proptest-book/intro.html)
75 |
76 | 6. Read the source code for the [compatibility test suite](compatibility-test/src).
77 |
78 | (Many of these examples are taken from or based on examples in
79 | [the proptest book](https://altsysrq.github.io/proptest-book/intro.html).)
80 |
81 | There is also [some limited documentation](https://project-oak.github.io/rust-verification-tools/about.html) of how this works.
82 |
83 | ## License
84 |
85 | Licensed under either of
86 |
87 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
88 | http://www.apache.org/licenses/LICENSE-2.0)
89 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or
90 | http://opensource.org/licenses/MIT)
91 |
92 | at your option.
93 |
94 | ## Acknowledgements
95 |
96 | The `propverify` crate is heavily based on the design and API of the wonderful
97 | [proptest](https://github.com/AltSysrq/proptest)
98 | property/fuzz-testing library.
99 | The implementation also borrows techniques, tricks and code
100 | from the implementation – you can learn a lot about how to write
101 | an embedded DSL from reading the proptest code.
102 |
103 | In turn, `proptest` was influenced by
104 | the [Rust port of QuickCheck](https://github.com/burntsushi/quickcheck)
105 | and
106 | the [Hypothesis](https://hypothesis.works/) fuzzing/property testing library for Python.
107 | (`proptest` also acknowledges `regex_generate` – but we have not yet implemented
108 | regex strategies for this library.)
109 |
110 | ## Known limitations
111 |
112 | This is not an officially supported Google product;
113 | this is an early release of a research project
114 | to enable experiments, feedback and contributions.
115 | It is probably not useful to use on real projects at this stage
116 | and it may change significantly in the future.
117 |
118 | Our current goal is to make `propverify` as compatible with
119 | `proptest` as possible but we are not there yet.
120 | The most obvious features that are not even implemented are
121 | support for
122 | using regular expressions for string strategies,
123 | the `Arbitrary` trait,
124 | `proptest-derive`.
125 |
126 | We would like the `propverify` library and the `cargo-verify` script
127 | to work with as many Rust verification tools as possible
128 | and we welcome pull requests to add support.
129 | We expect that this will require design/interface changes.
130 |
131 | ### Contribution
132 |
133 | Unless you explicitly state otherwise, any contribution intentionally
134 | submitted for inclusion in the
135 | work by you, as defined in the Apache-2.0 license, shall be dual licensed as
136 | above, without any
137 | additional terms or conditions.
138 |
139 | See [the contribution instructions](CONTRIBUTING.md) for further details.
140 |
--------------------------------------------------------------------------------
/cargo-verify/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "cargo-verify"
3 | version = "0.1.0"
4 | authors = ["Shaked Flur "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | ansi_term = "0.12"
11 | cargo_metadata = "0.12.3"
12 | glob = "0.3.0"
13 | lazy_static = "1.4.0"
14 | log = "0.4"
15 | num_cpus = "1.0"
16 | rayon = "1.5.0"
17 | regex = "1.4.3"
18 | rustc-demangle = "0.1"
19 | serde = { version = "1.0", features = ["derive"] }
20 | shell-escape = "0.1.5"
21 | stderrlog = "0.5"
22 | structopt = "0.3"
23 | tinytemplate = "1.1"
24 |
--------------------------------------------------------------------------------
/cargo-verify/rustfmt.toml:
--------------------------------------------------------------------------------
1 | # See more keys and their definitions at https://rust-lang.github.io/rustfmt
2 |
3 | # Use unstable features of rustfmt
4 | unstable_features = true
5 |
6 | merge_imports = true
7 | imports_granularity = "Crate"
8 | group_imports = "StdExternalCrate"
9 |
10 | enum_discrim_align_threshold = 20
11 | struct_field_align_threshold = 20
12 |
--------------------------------------------------------------------------------
/cargo-verify/src/backends_common.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use std::path::Path;
10 |
11 | use lazy_static::lazy_static;
12 | use log::info;
13 | use regex::Regex;
14 | use serde::Serialize;
15 | use tinytemplate::TinyTemplate;
16 |
17 | use crate::CVResult;
18 |
19 | /// Detect lines that match #[should_panic(expected = ...)] string.
20 | pub fn is_expected_panic(line: &str, expect: &Option<&str>, name: &str) -> bool {
21 | lazy_static! {
22 | static ref PANICKED: Regex = Regex::new(r" panicked at '([^']*)',\s+(.*)").unwrap();
23 | // This second form of panic is for multi-line panic messages
24 | // such as that generated by assert_eq!
25 | static ref PANICKED2: Regex = Regex::new(r" panicked at '([^']*)").unwrap();
26 | }
27 |
28 | if let Some(expect) = expect {
29 | if let Some(caps) = PANICKED.captures(line) {
30 | let message = caps.get(1).unwrap().as_str();
31 | let srcloc = caps.get(2).unwrap().as_str();
32 | if message.contains(expect) {
33 | info!(
34 | " {}: Detected expected failure '{}' at {}",
35 | name, message, srcloc
36 | );
37 | info!(" Error message: {}", line);
38 | return true;
39 | }
40 | } else if let Some(caps) = PANICKED2.captures(line) {
41 | let message = caps.get(1).unwrap().as_str();
42 | if message.contains(expect) {
43 | info!(" {}: Detected expected failure '{}'", name, message);
44 | info!(" Error message: {}", line);
45 | return true;
46 | }
47 | }
48 | }
49 |
50 | false
51 | }
52 |
53 | #[derive(Serialize)]
54 | struct FormatFlagContext<'a> {
55 | entry: &'a str,
56 | file: &'a str,
57 | output_dir: &'a str,
58 | }
59 |
60 | /// Format a user provided backend argument by replacing Handlebars with the appropriate values.
61 | pub fn format_flag(flag: &str, entry: &str, bcfile: &Path, out_dir: &Path) -> CVResult {
62 | let mut template = TinyTemplate::new();
63 | template.add_template("flag", flag)?;
64 |
65 | let context = FormatFlagContext {
66 | entry,
67 | file: &bcfile.to_string_lossy(),
68 | output_dir: &out_dir.to_string_lossy(),
69 | };
70 |
71 | let res = template.render("flag", &context)?;
72 |
73 | Ok(res)
74 | }
75 |
--------------------------------------------------------------------------------
/cargo-verify/src/proptest.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use log::warn;
10 |
11 | use crate::*;
12 |
13 | pub fn check_install() -> bool {
14 | true
15 | }
16 |
17 | /// Run cargo test
18 | pub fn run(opt: &Opt) -> CVResult {
19 | let mut cmd = Command::new("cargo");
20 | cmd.arg("test")
21 | .arg("--manifest-path")
22 | .arg(&opt.cargo_toml)
23 | .args(vec!["-v"; opt.verbose]);
24 |
25 | if !opt.features.is_empty() {
26 | cmd.arg("--features").arg(opt.features.join(","));
27 | }
28 |
29 | if opt.tests {
30 | cmd.arg("--tests");
31 | }
32 |
33 | for t in &opt.test {
34 | cmd.arg("--test").arg(t);
35 | }
36 |
37 | if opt.replay > 0 {
38 | assert!(opt.args.is_empty());
39 | cmd.arg("--").arg("--nocapture");
40 | } else if !opt.args.is_empty() {
41 | cmd.arg("--").args(&opt.args);
42 | }
43 |
44 | match cmd.output_info_ignore_exit(&opt, Verbosity::Major) {
45 | Err(e) => {
46 | warn!("Proptest failed '{:?}'", e);
47 | Ok(Status::Error)
48 | }
49 | Ok((_, stderr, success)) => {
50 | if !success {
51 | for l in stderr.lines() {
52 | if l.contains("with overflow") {
53 | return Ok(Status::Overflow);
54 | }
55 | }
56 | Ok(Status::Error)
57 | } else {
58 | Ok(Status::Verified)
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/cargo-verify/src/seahorn.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use std::{ffi::OsString, fs, path::Path, process::Command};
10 |
11 | use log::{info, warn};
12 |
13 | use crate::{utils::Append, *};
14 |
15 | /// Check if Seahorn is avilable.
16 | pub fn check_install() -> bool {
17 | // TODO: maybe it's better to check `seahorn --version`?
18 | let output = Command::new("which").arg("sea").output().ok();
19 |
20 | match output {
21 | Some(output) => output.status.success(),
22 | None => false,
23 | }
24 | }
25 |
26 | /// Run Seahorn
27 | pub fn verify(opt: &Opt, name: &str, entry: &str, bcfile: &Path) -> CVResult {
28 | let out_dir = opt.cargo_toml.with_file_name("seaout").append(name);
29 |
30 | // Ignoring result. We don't care if it fails because the path doesn't
31 | // exist.
32 | fs::remove_dir_all(&out_dir).unwrap_or_default();
33 | if out_dir.exists() {
34 | Err(format!(
35 | "Directory or file '{}' already exists, and can't be removed",
36 | out_dir.to_string_lossy()
37 | ))?
38 | }
39 | fs::create_dir_all(&out_dir)?;
40 |
41 | info!(" Running Seahorn to verify {}", name);
42 | info!(" file: {}", bcfile.to_string_lossy());
43 | info!(" entry: {}", entry);
44 | info!(" results: {}", out_dir.to_string_lossy());
45 |
46 | run(&opt, &name, &entry, &bcfile, &out_dir)
47 | }
48 |
49 | /// Return an int indicating importance of a line from KLEE's output
50 | /// Low numbers are most important, high numbers least important
51 | ///
52 | /// -1: script error (always shown)
53 | /// 1: brief description of error
54 | /// 2: long details about an error
55 | /// 3: warnings
56 | /// 4: non-Seahorn output
57 | /// 5: any other Seahorn output
58 | fn importance(line: &str, expect: &Option<&str>, name: &str) -> i8 {
59 | if line.starts_with("VERIFIER_EXPECT:") {
60 | 4
61 | } else if line == "sat" {
62 | 1
63 | } else if line.starts_with("Warning: Externalizing function:")
64 | || line.starts_with("Warning: not lowering an initializer for a global struct:")
65 | || (line.starts_with("Warning: found")
66 | && line.ends_with("possible reads of undefined values"))
67 | {
68 | 4
69 | } else if backends_common::is_expected_panic(&line, &expect, &name) || line == "unsat" {
70 | 5
71 | } else if line.starts_with("Warning:") {
72 | // Really high priority to force me to categorize it
73 | 0
74 | } else {
75 | // Remaining output is probably output from the application, stack dumps, etc.
76 | 3
77 | }
78 | }
79 |
80 | /// Run Seahorn and analyse its output.
81 | fn run(opt: &Opt, name: &str, entry: &str, bcfile: &Path, out_dir: &Path) -> CVResult {
82 | let verify_common_dir = match &opt.seahorn_verify_c_common_dir {
83 | Some(verify_common_dir) => verify_common_dir,
84 | None => Err("The '--seahorn-verify-c-common-dir' option is missing")?,
85 | };
86 |
87 | let mut cmd = Command::new("sea");
88 |
89 | let user_flags: Vec<_> = opt
90 | .backend_flags
91 | .iter()
92 | .map(|flag| backends_common::format_flag(&flag, &entry, &bcfile, &out_dir))
93 | .collect::>()?;
94 |
95 | if !opt.replace_backend_flags {
96 | cmd.arg("yama")
97 | .arg("-y")
98 | .arg(format!("{}/seahorn/sea_base.yaml", verify_common_dir))
99 | .arg("bpf")
100 | .arg(OsString::from("--temp-dir=").append(out_dir))
101 | .arg(String::from("--entry=") + entry)
102 | .args(user_flags)
103 | .arg(&bcfile);
104 | } else {
105 | cmd.args(user_flags);
106 | }
107 |
108 | let (stdout, stderr, _) = cmd.output_info_ignore_exit(&opt, Verbosity::Major)?;
109 |
110 | // We scan stderr for:
111 | // 1. Indications of the expected output (eg from #[should_panic])
112 | // 2. Indications of success/failure
113 | // 3. Information relevant at the current level of verbosity
114 | // 4. Statistics
115 |
116 | // Scan for expectation message
117 | let mut expect = None;
118 | for l in stderr.lines() {
119 | if l == "VERIFIER_EXPECT: should_panic" {
120 | expect = Some("");
121 | } else if let Some(e) = l
122 | .strip_prefix("VERIFIER_EXPECT: should_panic(expected = \"")
123 | .and_then(|l| l.strip_suffix("\")"))
124 | {
125 | info!("Expecting '{}'", e);
126 | expect = Some(e);
127 | }
128 | }
129 |
130 | // Scan for first message that indicates result
131 | let status = stderr
132 | .lines()
133 | .chain(stdout.lines())
134 | .find_map(|l| {
135 | if l.starts_with("VERIFIER_EXPECT:") {
136 | // don't confuse this line with an error!
137 | None
138 | } else if backends_common::is_expected_panic(&l, &expect, &name) {
139 | Some(Status::Verified)
140 | } else if l == "sat" {
141 | Some(Status::Error)
142 | } else if l == "unsat" {
143 | match expect {
144 | None => Some(Status::Verified),
145 | _ => Some(Status::Error),
146 | }
147 | } else {
148 | None
149 | }
150 | })
151 | .unwrap_or_else(|| {
152 | warn!("Unable to determine status of {}", name);
153 | Status::Unknown
154 | });
155 |
156 | info!(
157 | "Status: '{}' expected: '{}'",
158 | status,
159 | expect.unwrap_or("---")
160 | );
161 |
162 | // TODO: Scan for statistics
163 |
164 | for l in stderr.lines() {
165 | if importance(&l, &expect, &name) < opt.verbose as i8 {
166 | println!("{}", l);
167 | }
168 | }
169 |
170 | Ok(status)
171 | }
172 |
--------------------------------------------------------------------------------
/cargo-verify/src/smack.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use std::{ffi::OsString, fs, path::Path, process::Command};
10 |
11 | use log::{info, warn};
12 |
13 | use crate::{utils::Append, *};
14 |
15 | /// Check if SMACK is available.
16 | pub fn check_install() -> bool {
17 | let output = Command::new("which").arg("smack").output().ok();
18 |
19 | match output {
20 | Some(output) => output.status.success(),
21 | None => false,
22 | }
23 | }
24 |
25 | /// Run SMACK
26 | pub fn verify(opt: &Opt, name: &str, entry: &str, bcfile: &Path) -> CVResult {
27 | let out_dir = opt.cargo_toml.with_file_name("smackout").append(name);
28 |
29 | // Ignoring result. We don't care if it fails because the path doesn't
30 | // exist.
31 | fs::remove_dir_all(&out_dir).unwrap_or_default();
32 | if out_dir.exists() {
33 | Err(format!(
34 | "Directory or file '{}' already exists, and can't be removed",
35 | out_dir.to_string_lossy()
36 | ))?
37 | }
38 | fs::create_dir_all(&out_dir)?;
39 |
40 | info!(" Running SMACK to verify {}", name);
41 | info!(" file: {}", bcfile.to_string_lossy());
42 | info!(" entry: {}", entry);
43 | info!(" results: {}", out_dir.to_string_lossy());
44 |
45 | run(&opt, &name, &entry, &bcfile, &out_dir)
46 | }
47 |
48 | /// Run Smack and analyse its output.
49 | fn run(opt: &Opt, name: &str, entry: &str, bcfile: &Path, out_dir: &Path) -> CVResult {
50 | let mut cmd = Command::new("smack");
51 |
52 | let user_flags: Vec<_> = opt
53 | .backend_flags
54 | .iter()
55 | .map(|flag| backends_common::format_flag(&flag, &entry, &bcfile, &out_dir))
56 | .collect::>()?;
57 |
58 | cmd.arg("--verifier=boogie")
59 | .args(user_flags)
60 | .arg(String::from("--entry-points=") + entry)
61 | .arg(bcfile);
62 | let (stdout, stderr, _) = cmd.output_info_ignore_exit(&opt, Verbosity::Major)?;
63 |
64 | // Scan for result mesage
65 | let status = stderr
66 | .lines()
67 | .chain(stdout.lines())
68 | .find_map(|l| {
69 | if l.starts_with("SMACK found no errors") {
70 | Some(Status::Verified)
71 | } else if l.starts_with("SMACK found an error") {
72 | Some(Status::Error)
73 | } else {
74 | None
75 | }
76 | })
77 | .unwrap_or_else(|| {
78 | warn!("Unable to determine status of {}", name);
79 | Status::Unknown
80 | });
81 |
82 | Ok(status)
83 | }
84 |
--------------------------------------------------------------------------------
/cargo-verify/src/utils.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | ////////////////////////////////////////////////////////////////////////////////
10 | // Put here reusable general purpose utility functions (nothing that is part of
11 | // core functionality).
12 | ////////////////////////////////////////////////////////////////////////////////
13 |
14 | use std::{
15 | borrow::{Borrow, ToOwned},
16 | ffi::{OsStr, OsString},
17 | path::{Path, PathBuf},
18 | };
19 |
20 | /// `info_at!(&opt, level, ...)` will print the formatted message `...` if
21 | /// verbosity level is `level` or higher.
22 | macro_rules! info_at {
23 | ($opt:expr, $lvl:expr, $($arg:tt)+) => ({
24 | let lvl = $lvl;
25 | if lvl <= $opt.verbosity {
26 | println!($($arg)+);
27 | }
28 | });
29 | }
30 |
31 | /// encoding_rs (https://docs.rs/encoding_rs/), seems to be the standard crate
32 | /// for encoding/decoding, has this to say about ISO-8859-1: "ISO-8859-1 does not
33 | /// exist as a distinct encoding from windows-1252 in the Encoding
34 | /// Standard. Therefore, an encoding that maps the unsigned byte value to the
35 | /// same Unicode scalar value is not available via Encoding in this crate."
36 | /// The following is from https://stackoverflow.com/a/28175593
37 | pub fn from_latin1(s: &[u8]) -> String {
38 | s.iter().map(|&c| c as char).collect()
39 | }
40 |
41 | /// The Append trait lets you chain `append` calls where usually you would have
42 | /// to mutate (e.g. using `push`).
43 | /// Example:
44 | /// assert_eq!(String::from("foo").append("bar"), { let mut x = String::from("foo"); x.push_str("bar"); x })
45 | pub trait Append: Sized
46 | where
47 | Segment: ToOwned,
48 | Self: Borrow,
49 | {
50 | fn append(self: Self, s: impl AsRef) -> Self;
51 | }
52 |
53 | /// Concatenate `s` to the end of `self`.
54 | impl Append for String {
55 | fn append(mut self: String, s: impl AsRef) -> String {
56 | self.push_str(s.as_ref());
57 | self
58 | }
59 | }
60 |
61 | /// Concatenate `s` to the end of `self`.
62 | impl Append for OsString {
63 | fn append(mut self: OsString, s: impl AsRef) -> OsString {
64 | self.push(s);
65 | self
66 | }
67 | }
68 |
69 | /// Add `s` to the end of `self`, as a new component.
70 | impl Append for PathBuf {
71 | fn append(mut self: PathBuf, s: impl AsRef) -> PathBuf {
72 | self.push(s);
73 | self
74 | }
75 | }
76 |
77 | /// Add `ext` to `file` just before the extension.
78 | /// Example:
79 | /// assert_eq!(add_pre_ext(&PathBuf::from("foo.bar"), "baz"), PathBuf::from("foo.baz.bar"))
80 | pub fn add_pre_ext(file: &Path, ext: impl AsRef) -> PathBuf {
81 | assert!(file.is_file());
82 |
83 | let new_ext = match file.extension() {
84 | None => OsString::from(ext.as_ref()),
85 | Some(old_ext) => OsString::from(ext.as_ref()).append(".").append(old_ext),
86 | };
87 | let mut new_file = PathBuf::from(&file);
88 | new_file.set_extension(&new_ext);
89 | new_file
90 | }
91 |
--------------------------------------------------------------------------------
/compatibility-test/.gitignore:
--------------------------------------------------------------------------------
1 | proptest-regressions/
2 |
--------------------------------------------------------------------------------
/compatibility-test/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "compatibility-test"
3 | version = "0.1.0"
4 | authors = [
5 | "Alastair Reid ",
6 | "Shaked Flur "
7 | ]
8 | edition = "2018"
9 | description = "Tests for both the propverify and the proptest crates - to check compatibility."
10 |
11 | [dependencies]
12 |
13 | [target.'cfg(verify)'.dependencies]
14 | propverify = { path="/home/rust-verification-tools/propverify" }
15 |
16 | [target.'cfg(not(verify))'.dependencies]
17 | proptest = { version = "*" }
18 |
19 | [features]
20 | verifier-klee = ["propverify/verifier-klee"]
21 | verifier-crux = ["propverify/verifier-crux"]
22 | verifier-smack = ["propverify/verifier-smack"]
23 |
--------------------------------------------------------------------------------
/compatibility-test/src/collections.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | ////////////////////////////////////////////////////////////////
11 | // Proptest-based tests to check collection support
12 | ////////////////////////////////////////////////////////////////
13 |
14 | #[cfg(not(verify))]
15 | use proptest::prelude::*;
16 | #[cfg(verify)]
17 | use propverify::prelude::*;
18 |
19 | proptest! {
20 | #[test]
21 | fn binary_heap(v in prop::collection::binary_heap(0..100u32, 5)) {
22 | assert!(v.len() == 5);
23 | for x in v.iter() {
24 | assert!(*x < 100);
25 | }
26 |
27 | // check first element larger than rest
28 | let mut v1 = v;
29 | let x0 = v1.pop().unwrap();
30 | for x in v1.iter() {
31 | assert!(*x <= x0);
32 | }
33 | }
34 | }
35 |
36 | proptest! {
37 | #[test]
38 | #[should_panic(expected = "assertion failed")]
39 | fn binary_heap_fail1(v in prop::collection::binary_heap(0..100u32, 5)) {
40 | for x in v.iter() {
41 | assert!(*x < 10);
42 | }
43 | }
44 | }
45 |
46 | proptest! {
47 | #[test]
48 | #[should_panic(expected = "assertion failed")]
49 | fn binary_heap_fail2(v in prop::collection::binary_heap(0..100u32, 5)) {
50 | // check first element smaller than rest
51 | let mut v1 = v;
52 | let x0 = v1.pop().unwrap();
53 | for x in v1.iter() {
54 | assert!(*x < x0);
55 | }
56 | }
57 | }
58 |
59 | proptest! {
60 | #[test]
61 | fn btree_map(v in prop::collection::btree_map(-5..5i32, 10..20u32, 5)) {
62 |
63 | // Note that key collisions may reduce the number of entries
64 | // so the following assertion will fail.
65 | // assert!(v.len() == 5);
66 | assert!(v.len() <= 5);
67 |
68 | for (key, value) in v.iter() {
69 | assert!((-5..5i32).contains(key));
70 | assert!((*value) > 5);
71 | }
72 | }
73 | }
74 |
75 | proptest! {
76 | #[test]
77 | #[should_panic(expected = "assertion failed")]
78 | fn btree_map_fail1(v in prop::collection::btree_map(-5..5i32, 10..20u32, 5)) {
79 | for (key, _) in v.iter() {
80 | assert!((0..5i32).contains(key));
81 | }
82 | }
83 | }
84 |
85 | proptest! {
86 | #[test]
87 | #[should_panic(expected = "assertion failed")]
88 | fn btree_map_fail2(v in prop::collection::btree_map(-5..5i32, 10..20u32, 5)) {
89 | for (_, value) in v.iter() {
90 | assert!((*value) > 15);
91 | }
92 | }
93 | }
94 |
95 | proptest! {
96 | #[test]
97 | fn btree_set(v in prop::collection::btree_set(-100..100i32, 5)) {
98 |
99 | // Note that key collisions may reduce the number of entries
100 | // so the following assertion will fail.
101 | // assert!(v.len() == 5);
102 | assert!(v.len() <= 5);
103 |
104 | for x in v.iter() {
105 | assert!((-100..100i32).contains(x));
106 | }
107 | }
108 | }
109 |
110 | proptest! {
111 | #[test]
112 | #[should_panic(expected = "assertion failed")]
113 | fn btree_set_fail1(v in prop::collection::btree_set(-100..100i32, 5)) {
114 | for x in v.iter() {
115 | assert!((0..100i32).contains(x));
116 | }
117 | }
118 | }
119 |
120 | proptest! {
121 | #[test]
122 | fn linked_list(v in prop::collection::linked_list(0..10u32, 5)) {
123 | assert!(v.len() == 5);
124 | for x in &v {
125 | assert!(*x < 10);
126 | }
127 | }
128 | }
129 |
130 | proptest! {
131 | #[test]
132 | #[should_panic(expected = "assertion failed")]
133 | fn linked_list_fail1(v in prop::collection::linked_list(0..10u32, 5)) {
134 | for x in &v {
135 | assert!(*x < 5);
136 | }
137 | }
138 | }
139 |
140 | proptest! {
141 | #[test]
142 | fn vec_deque(v in prop::collection::vec_deque(0..10u32, 5)) {
143 | assert!(v.len() == 5);
144 | for x in &v {
145 | assert!(*x < 10);
146 | }
147 | }
148 | }
149 |
150 | proptest! {
151 | #[test]
152 | #[should_panic(expected = "assertion failed")]
153 | fn vec_deque_fail1(v in prop::collection::vec_deque(0..10u32, 5)) {
154 | for x in &v {
155 | assert!(*x < 5);
156 | }
157 | }
158 | }
159 |
160 | proptest! {
161 | #[test]
162 | fn vec(v in prop::collection::vec(0..10u32, 5)) {
163 | assert!(v.len() == 5);
164 | for x in &v {
165 | assert!(*x < 10);
166 | }
167 | }
168 | }
169 |
170 | proptest! {
171 | #[test]
172 | #[should_panic(expected = "assertion failed")]
173 | fn vec_fail1(v in prop::collection::vec(0..10u32, 5)) {
174 | for x in &v {
175 | assert!(*x < 5);
176 | }
177 | }
178 | }
179 |
180 | ////////////////////////////////////////////////////////////////
181 | // End
182 | ////////////////////////////////////////////////////////////////
183 |
--------------------------------------------------------------------------------
/compatibility-test/src/compose.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | ////////////////////////////////////////////////////////////////
11 | // Proptest-based tests exploring how to use prop_compose
12 | ////////////////////////////////////////////////////////////////
13 |
14 | #[cfg(not(verify))]
15 | use proptest::prelude::*;
16 | #[cfg(verify)]
17 | use propverify::prelude::*;
18 |
19 | #[cfg(test)]
20 | mod test {
21 | use super::*;
22 | use core::fmt::Debug;
23 |
24 | #[derive(Clone, Debug)]
25 | struct MyStruct {
26 | x: u32,
27 | y: u32,
28 | }
29 |
30 | // First version - written by hand
31 | fn my_struct_strategy1(max_integer: u32) -> impl Strategy {
32 | let strat = (0..max_integer, 0..max_integer);
33 | Strategy::prop_map(strat, move |(x, y)| MyStruct { x, y })
34 | }
35 |
36 | proptest! {
37 | #[test]
38 | fn struct_test1(s in my_struct_strategy1(10)) {
39 | assert!(s.x < 10);
40 | assert!(s.y < 10);
41 | }
42 | }
43 |
44 | // identical to my_struct_strategy1 but written using prop_compose!
45 | prop_compose! {
46 | fn my_struct_strategy2(max_integer: u32)
47 | (x in 0..max_integer, y in 0..max_integer)
48 | -> MyStruct {
49 | MyStruct { x, y, }
50 | }
51 | }
52 |
53 | proptest! {
54 | #[test]
55 | fn struct_test2(s in my_struct_strategy2(10)) {
56 | assert!(s.x < 10);
57 | assert!(s.y < 10);
58 | }
59 | }
60 | }
61 |
62 | ////////////////////////////////////////////////////////////////
63 | // End
64 | ////////////////////////////////////////////////////////////////
65 |
--------------------------------------------------------------------------------
/compatibility-test/src/dynamic.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | ////////////////////////////////////////////////////////////////
11 | // Proptest-based tests exploring how to use proptest with
12 | // trait objects
13 | ////////////////////////////////////////////////////////////////
14 |
15 | #[cfg(not(verify))]
16 | use proptest::prelude::*;
17 | #[cfg(verify)]
18 | use propverify::prelude::*;
19 |
20 | ////////////////////////////////////////////////////////////////
21 | // A trait and a couple of implementations
22 | ////////////////////////////////////////////////////////////////
23 |
24 | #[cfg(test)]
25 | mod foo {
26 | use core::fmt::Debug;
27 |
28 | pub trait Foo: Debug {
29 | fn foo(&self) -> i32;
30 | }
31 |
32 | // A boxed trait object type
33 | pub type FB = Box;
34 |
35 | #[derive(Debug)]
36 | struct A {
37 | a: i8,
38 | }
39 | impl Foo for A {
40 | fn foo(&self) -> i32 {
41 | self.a.into()
42 | }
43 | }
44 | pub fn a_to_foo(a: i8) -> FB {
45 | Box::new(A { a })
46 | }
47 |
48 | #[derive(Debug)]
49 | struct B {
50 | b: i16,
51 | }
52 | impl Foo for B {
53 | fn foo(&self) -> i32 {
54 | self.b.into()
55 | }
56 | }
57 | pub fn b_to_foo(b: i16) -> FB {
58 | Box::new(B { b })
59 | }
60 | }
61 |
62 | ////////////////////////////////////////////////////////////////
63 | // Proptest-based tests exploring how to use proptest with
64 | // trait objects
65 | ////////////////////////////////////////////////////////////////
66 |
67 | #[cfg(test)]
68 | mod test {
69 | use super::*;
70 |
71 | proptest! {
72 | #[test]
73 | fn dynamic(x in (0..10i8).prop_map(foo::a_to_foo).boxed()) {
74 | // println!("x = {:?}", x);
75 | let y : i32 = x.foo();
76 | assert!(y != 15);
77 | assert!((0..10).contains(&y));
78 | }
79 | }
80 |
81 | proptest! {
82 | #[test]
83 | fn dynamic_union(r in (0..10i8).prop_map(|x| foo::a_to_foo(x)).boxed().prop_union(
84 | (1000i16..).prop_map(foo::b_to_foo).boxed())) {
85 | // println!("r = {:?}", r);
86 | assert!(r.foo() < 10 || r.foo() > 100);
87 | }
88 | }
89 |
90 | proptest! {
91 | #[test]
92 | fn dynamic_oneof(r in prop_oneof![
93 | (0..10i8).prop_map(foo::a_to_foo),
94 | (1000i16..).prop_map(foo::b_to_foo)]) {
95 | // println!("r = {:?}", r);
96 | assert!(r.foo() < 10 || r.foo() > 100);
97 | }
98 | }
99 | }
100 |
101 | ////////////////////////////////////////////////////////////////
102 | // End
103 | ////////////////////////////////////////////////////////////////
104 |
--------------------------------------------------------------------------------
/compatibility-test/src/enumeration.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | ////////////////////////////////////////////////////////////////
11 | // Proptest-based tests exploring how to use proptest with
12 | // enumerations
13 | ////////////////////////////////////////////////////////////////
14 |
15 | #[cfg(not(verify))]
16 | use proptest::prelude::*;
17 | #[cfg(verify)]
18 | use propverify::prelude::*;
19 |
20 | ////////////////////////////////////////////////////////////////
21 | // An enumeration type
22 | //
23 | // Example taken from proptest
24 | ////////////////////////////////////////////////////////////////
25 |
26 | #[cfg(test)]
27 | mod test {
28 | use super::*;
29 | use core::fmt::Debug;
30 |
31 | #[derive(Clone, Debug)]
32 | enum MyEnum {
33 | Big(u64),
34 | Medium(u32),
35 | Little(i16),
36 | }
37 |
38 | fn my_enum_strategy(s: u8) -> impl Strategy {
39 | prop_oneof![
40 | (0..i16::from(s)).prop_map(MyEnum::Little),
41 | (0..u32::from(s)).prop_map(MyEnum::Medium),
42 | (0..u64::from(s)).prop_map(MyEnum::Big),
43 | ]
44 | }
45 |
46 | proptest! {
47 | #[test]
48 | fn enum_test1(x in my_enum_strategy(10)) {
49 | match x {
50 | MyEnum::Big(b) => assert!(b < 10),
51 | MyEnum::Medium(m) => assert!(m < 10),
52 | MyEnum::Little(l) => assert!(l < 10)
53 | }
54 | }
55 | }
56 | }
57 |
58 | ////////////////////////////////////////////////////////////////
59 | // End
60 | ////////////////////////////////////////////////////////////////
61 |
--------------------------------------------------------------------------------
/compatibility-test/src/main.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | ////////////////////////////////////////////////////////////////
11 | // Test compatibility of the propverify crate with
12 | // the original proptest crate.
13 | //
14 | // Some tests in this crate are based on proptest examples.
15 | ////////////////////////////////////////////////////////////////
16 |
17 | #![allow(unused_imports)]
18 |
19 | #[cfg(not(verify))]
20 | use proptest::prelude::*;
21 | #[cfg(verify)]
22 | use propverify::prelude::*;
23 |
24 | mod collections;
25 | mod compose;
26 | mod dynamic;
27 | mod enumeration;
28 |
29 | // A simple test of the propverify/proptest library
30 | proptest! {
31 | fn main(
32 | a in 4..8u32,
33 | b in 5..9u32)
34 | {
35 | let r = a*b;
36 | assert!(20 <= r && r <= 56);
37 | }
38 | }
39 |
40 | #[cfg(test)]
41 | mod ranges {
42 | use super::*;
43 |
44 | proptest! {
45 | #[test]
46 | #[should_panic(expected = "overflow")]
47 | fn i64_abs_is_never_negative(a in (std::i64::MIN .. std::i64::MAX)) {
48 | // This actually fails if a == i64::MIN, but randomly picking one
49 | // specific value out of 2⁶⁴ is overwhelmingly unlikely.
50 | assert!(a.abs() >= 0);
51 | }
52 | }
53 |
54 | proptest! {
55 | #[test]
56 | fn range1(
57 | a in (std::i32::MIN/2 .. std::i32::MAX/2),
58 | b in (std::i32::MIN/2 .. std::i32::MAX/2),
59 | ) {
60 | assert_eq!(a + b, b + a);
61 | }
62 | }
63 |
64 | proptest! {
65 | #[test]
66 | fn range2(a in 0..10u32, b in 10..20u32) {
67 | assert_ne!(a, b)
68 | }
69 | }
70 |
71 | proptest! {
72 | #[test]
73 | #[should_panic(expected = "attempt to add with overflow")]
74 | fn overflow1(
75 | a in 0 .. std::i32::MAX,
76 | b in 0 .. std::i32::MAX,
77 | ) {
78 | // Note that overflow tests have to be fairly unsubtle or
79 | // fuzzing can miss it. eg catching "a+1 overflows" is
80 | // unlikely beyond 8-bit ints.
81 | assert_eq!(a + b, b + a);
82 | }
83 | }
84 | }
85 |
86 | #[cfg(test)]
87 | mod tuples {
88 | use super::*;
89 |
90 | proptest! {
91 | #[test]
92 | fn tuple2((a, b) in (0u32.., 0u32..)) {
93 | assert_eq!((a <= b), (b >= a));
94 | }
95 | }
96 | }
97 |
98 | #[cfg(test)]
99 | mod prop {
100 | use super::*;
101 |
102 | proptest! {
103 | #[test]
104 | fn filter_map(a in (0u32..1000).prop_filter_map("%2", |x| if x % 2 == 0 { Some(x*2) } else { None })) {
105 | assert!(a % 4 == 0);
106 | }
107 | }
108 |
109 | proptest! {
110 | #[test]
111 | #[should_panic(expected = "assertion failed")]
112 | fn filter_map_fail1(a in (0u32..1000).prop_filter_map("%2", |x| if x % 2 == 0 { Some(x*2) } else { None })) {
113 | assert!(a % 8 == 0);
114 | }
115 | }
116 |
117 | proptest! {
118 | #[test]
119 | fn filter(a in (0..).prop_filter("%4", |x| x % 4 == 0)) {
120 | assert!(a % 2 == 0);
121 | }
122 | }
123 |
124 | proptest! {
125 | #[test]
126 | fn flat_map((a, b) in (1..65536).prop_flat_map(|a| (Just(a), 0..a))) {
127 | assert!(a > b);
128 | }
129 | }
130 |
131 | proptest! {
132 | #[test]
133 | #[should_panic(expected = "assertion failed")]
134 | fn flat_map_fail1((a, b) in (1..65536).prop_flat_map(|a| (Just(a), 0..a))) {
135 | assert!(a <= b);
136 | }
137 | }
138 |
139 | proptest! {
140 | #[test]
141 | fn ind_flat_map((a, b) in (1..65536).prop_ind_flat_map(|a| (Just(a), 0..a))) {
142 | assert!(a > b);
143 | }
144 | }
145 |
146 | proptest! {
147 | #[test]
148 | fn ind_flat_map2((a, b) in (1..65536).prop_ind_flat_map2(|a| (0..a))) {
149 | assert!(a > b);
150 | }
151 | }
152 |
153 | proptest! {
154 | #[test]
155 | #[should_panic(expected = "assertion failed")]
156 | fn ind_flat_map2_fail1((a, b) in (1..65536).prop_ind_flat_map2(|a| (0..a))) {
157 | assert!(a <= b);
158 | }
159 | }
160 |
161 | proptest! {
162 | #[test]
163 | fn map_into(a in (0u8..).prop_map_into::()) {
164 | assert!(a < 256);
165 | }
166 | }
167 |
168 | proptest! {
169 | #[test]
170 | fn map(a in (0..10i32).prop_map(|x| x+50)) {
171 | assert!(a >= 50);
172 | }
173 | }
174 |
175 | proptest! {
176 | #[test]
177 | #[should_panic(expected = "assertion failed")]
178 | fn map_fail1(a in (0..10i32).prop_map(|x| x+50)) {
179 | assert!(a < 10);
180 | }
181 | }
182 |
183 | proptest! {
184 | #[test]
185 | #[should_panic(expected = "assertion failed")]
186 | fn map_into_fail1(a in (0u16..).prop_map_into::()) {
187 | assert!(a < 256);
188 | }
189 | }
190 | }
191 |
192 | #[cfg(test)]
193 | mod union {
194 | use super::*;
195 |
196 | proptest! {
197 | #[test]
198 | fn union1(v in prop_oneof![0..10u32, 30u32..]) {
199 | assert!((0..10).contains(&v) || (30..).contains(&v));
200 | }
201 | }
202 |
203 | proptest! {
204 | #[test]
205 | #[should_panic(expected = "assertion failed")]
206 | fn union_fail1(a in (0..10i32).prop_union(20..30i32)) {
207 | assert!(a != 25);
208 | }
209 | }
210 | }
211 |
212 | ////////////////////////////////////////////////////////////////
213 | // End
214 | ////////////////////////////////////////////////////////////////
215 |
--------------------------------------------------------------------------------
/compatibility-test/src/shouldfail.rs:
--------------------------------------------------------------------------------
1 | #[cfg(test)]
2 |
3 | mod ranges {
4 |
5 | proptest! {
6 | #[test]
7 | #[should_panic]
8 | fn overflow1(
9 | a in 0 .. std::i32::MAX,
10 | b in 0 .. std::i32::MAX,
11 | ) {
12 | assert_eq!(a + b, b + a);
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demos/README.md:
--------------------------------------------------------------------------------
1 | # Demo code
2 |
3 | This directory contains demonstration code.
4 |
5 | - `demos/simple/klee`: using KLEE directly to verify Rust code.
6 | See [docs/using-klee](../docs/using-klee.md) for description.
7 | - `demos/simple/annotations`: using the `verification-annotations` crate with
8 | `cargo-verify`.
9 | See [docs/using-annotations](../docs/using-annotations.md) for description.
10 |
11 | - `demos/simple/ffi`: using KLEE directly to verify Rust+C crates (that use the
12 | FFI).
13 | See [docs/using-ffi](../docs/using-ffi.md) for description.
14 |
--------------------------------------------------------------------------------
/demos/bottlenecks/bornholt2018-1/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "bornholt2018-1"
3 | version = "0.1.0"
4 | authors = ["Shaked Flur "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 |
11 | [target.'cfg(verify)'.dependencies]
12 | propverify = { path="../../../propverify" }
13 |
14 | [target.'cfg(not(verify))'.dependencies]
15 | proptest = { version = "*" }
16 |
17 | [features]
18 | verifier-klee = ["propverify/verifier-klee"]
19 | verifier-crux = ["propverify/verifier-crux"]
20 | verifier-seahorn = ["propverify/verifier-seahorn"]
21 |
--------------------------------------------------------------------------------
/demos/bottlenecks/bornholt2018-1/src/main.rs:
--------------------------------------------------------------------------------
1 | // Based on fig.1 from: James Bornholt and Emina Torlak. 2018. Finding code that
2 | // explodes under symbolic evaluation. Proc. ACM Program. Lang. 2, OOPSLA,
3 | // Article 149 (November 2018), 26 pages. DOI:https://doi.org/10.1145/3276519
4 |
5 | #![feature(unchecked_math)]
6 |
7 | #[cfg(not(verify))]
8 | use proptest::prelude::*;
9 | #[cfg(verify)]
10 | use propverify::prelude::*;
11 |
12 | // The tests below check that the sum of any n ≤ N even integers is also even.
13 |
14 | fn is_even(x: i32) -> bool {
15 | x % 2 == 0
16 | }
17 |
18 | const N: usize = 5;
19 |
20 | // proptest! {
21 | // #[test]
22 | // fn t0(xs in prop::collection::vec(0i32..1000, N), n in 0usize..N+1) {
23 | // verifier::assert!(false);
24 | // }
25 | // }
26 |
27 | proptest! {
28 | #[test]
29 | fn t1(xs in prop::collection::vec(0i32..1000, N), n in 0usize..N+1) {
30 | let ys = xs.into_iter().filter(|x| is_even(*x));
31 | let zs = ys.take(n);
32 | prop_assert!(is_even(zs.sum::()));
33 | }
34 | }
35 |
36 | proptest! {
37 | #[test]
38 | fn t2(xs in prop::collection::vec(0i32..1000, N), n in 0usize..N+1) {
39 | let zs = xs.into_iter().take(n);
40 | prop_assume!(zs.clone().all(is_even));
41 | prop_assert!(is_even(zs.sum::()));
42 | }
43 | }
44 |
45 | proptest! {
46 | #[test]
47 | fn t3(xs in prop::collection::vec(0i32..1000, N), n in 0usize..N+1) {
48 | let zs: Vec<_> = xs.into_iter().take(n).collect();
49 | prop_assume!(zs.iter().all(|x| is_even(*x)));
50 | prop_assert!(is_even(zs.iter().sum::()));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/demos/bottlenecks/merging/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "merging"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
11 |
12 | [features]
13 | verifier-klee = ["verification-annotations/verifier-klee"]
14 | verifier-crux = ["verification-annotations/verifier-crux"]
15 | verifier-seahorn = ["verification-annotations/verifier-seahorn"]
16 |
--------------------------------------------------------------------------------
/demos/bottlenecks/merging/src/main.rs:
--------------------------------------------------------------------------------
1 | /// Test the impact of path merging.
2 | ///
3 | /// This is a scaling test to explore path explosions
4 | /// using the canonical symbolic execution example of
5 | /// a loop with multiple branches in it which results
6 | /// in 2^N paths unless merging is used.
7 | ///
8 | /// Running this test on KLEE with
9 | ///
10 | /// cargo verify --backend=klee --tests -vv --backend-flags=--use-merge |& grep 'generated tests'
11 | ///
12 | /// should result in
13 | ///
14 | /// test_original: {"generated tests": 1024, "total instructions": 709566, "completed paths": 4093}
15 | /// test_merged: {"generated tests": 1, "completed paths": 41, "total instructions": 11852}
16 | ///
17 | /// Indicating that the original version suffers from a path explosion and generates
18 | /// more tests, executes more instructions and explores more paths than the merged version.
19 | use verification_annotations::prelude::*;
20 |
21 | fn main() {
22 | println!("Hello, world!");
23 | }
24 |
25 | const N: usize = 10;
26 |
27 | /// Test the impact of not using path merging.
28 | ///
29 | /// The critical part of this example is the second loop
30 | /// that contains multiple branches where the branches depend
31 | /// on symbolic expressions.
32 | ///
33 | /// On a classic symbolic execution tool, this will result in
34 | /// 2^N paths.
35 | #[test]
36 | fn test_original() {
37 | // An array
38 | let mut a = [0u32; N];
39 |
40 | // Set each element of array to a symbolic value
41 | for i in &mut a {
42 | *i = u32::abstract_value();
43 | }
44 |
45 | // A loop containing two branches - this will cause a performance problem
46 | // for conventional symbolic execution.
47 | for x in &a {
48 | verifier::assume((5..10).contains(x) || (15..20).contains(x))
49 | }
50 |
51 | // A true assertion about an arbitrary element of the array
52 | verifier::assert!(a[3] < 20);
53 | }
54 |
55 | /// Test the impact of using path merging.
56 | ///
57 | /// This test reduces the number of paths and instructions executed by merging
58 | /// all the paths forked inside the loop.
59 | ///
60 | /// There should be just one path when verified using KLEE with --use-merge
61 | #[test]
62 |
63 | /// The test depends on KLEE-specific features
64 | #[cfg(feature = "verifier-klee")]
65 | fn test_merged() {
66 | // An array
67 | let mut a = [0u32; N];
68 |
69 | // Set each element of array to a symbolic value
70 | for i in 0..a.len() {
71 | a[i] = u32::abstract_value();
72 | }
73 |
74 | // A loop containing two branches - this will cause a performance problem
75 | // for conventional symbolic execution.
76 | for x in a.iter() {
77 | verifier::coherent! {{
78 | verifier::assume((5..10).contains(x) || (15..20).contains(x))
79 | }}
80 | }
81 |
82 | // A true assertion about an arbitrary element of the array
83 | verifier::assert!(a[3] < 20);
84 | }
85 |
--------------------------------------------------------------------------------
/demos/bottlenecks/regex/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "regex"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
11 | regex = "1.4"
12 |
13 | [features]
14 | verifier-klee = ["verification-annotations/verifier-klee"]
15 | verifier-crux = ["verification-annotations/verifier-crux"]
16 | verifier-seahorn = ["verification-annotations/verifier-seahorn"]
17 |
--------------------------------------------------------------------------------
/demos/bottlenecks/regex/src/main.rs:
--------------------------------------------------------------------------------
1 | /// Test the use of regular expressions
2 | ///
3 | /// This test checks three things
4 | ///
5 | /// 1. Feature support for hand-vectorized code that
6 | /// includes a "slow path" if vector instructions are not
7 | /// available.
8 | /// (We are testing that the "fast path" is ignored.)
9 | ///
10 | /// 2. Feature support for an aligned memory allocator.
11 | /// (This is the part of the hand-vectorized code that we
12 | /// cannot disable.)
13 | ///
14 | /// 3. A path explosion in the handling of regular expressions.
15 | /// At present, this explosion is not fixed and we keep the
16 | /// strings very short to keep execution time reasonable.
17 | use regex::Regex;
18 | use verification_annotations::verifier;
19 |
20 | fn main() {
21 | println!("Hello, world!");
22 | }
23 |
24 | const N: usize = 2;
25 |
26 | /// Test use of regular expressions
27 | #[cfg_attr(not(feature = "verifier-crux"), test)]
28 | #[cfg_attr(feature = "verifier-crux", crux_test)]
29 | fn regex_ok() {
30 | let a = verifier::verifier_nondet_ascii_string(N);
31 |
32 | if verifier::is_replay() {
33 | println!("Value a = {:?}", a);
34 | }
35 |
36 | verifier::assume(Regex::new(r"[0-1]{2}").unwrap().is_match(&a));
37 |
38 | let i: u32 = a.parse().unwrap();
39 | verifier::assert!(i <= 11);
40 | }
41 |
42 | /// Test use of regular expressions
43 | #[cfg_attr(not(feature = "verifier-crux"), test)]
44 | #[cfg_attr(feature = "verifier-crux", crux_test)]
45 | fn regex_should_fail() {
46 | verifier::expect(Some("assertion failed"));
47 | let a = verifier::verifier_nondet_ascii_string(N);
48 |
49 | if verifier::is_replay() {
50 | println!("Value a = {:?}", a);
51 | }
52 |
53 | verifier::assume(Regex::new(r"[0-1]{2}").unwrap().is_match(&a));
54 |
55 | let i: u32 = a.parse().unwrap();
56 | verifier::assert!(i < 11);
57 | }
58 |
--------------------------------------------------------------------------------
/demos/simple/annotations/.gitignore:
--------------------------------------------------------------------------------
1 | out1
2 | out2
3 |
--------------------------------------------------------------------------------
/demos/simple/annotations/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "try-verifier"
3 | version = "0.1.0"
4 | authors = ["adreid"]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 |
11 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
12 |
13 | [features]
14 | verifier-klee = ["verification-annotations/verifier-klee"]
15 | verifier-crux = ["verification-annotations/verifier-crux"]
16 | verifier-seahorn = ["verification-annotations/verifier-seahorn"]
17 |
--------------------------------------------------------------------------------
/demos/simple/annotations/src/main.rs:
--------------------------------------------------------------------------------
1 | use verification_annotations::prelude::*;
2 |
3 | #[cfg_attr(feature = "verifier-crux", crux_test)]
4 | #[cfg_attr(not(feature = "verifier-crux"), test)]
5 | fn t1() {
6 | let a = u32::abstract_value();
7 | let b = u32::abstract_value();
8 | verifier::assume(1 <= a && a <= 1000);
9 | verifier::assume(1 <= b && b <= 1000);
10 | if verifier::is_replay() {
11 | eprintln!("Test values: a = {}, b = {}", a, b);
12 | }
13 | let r = a * b;
14 | verifier::assert!(1 <= r && r < 1000000);
15 | }
16 |
--------------------------------------------------------------------------------
/demos/simple/annotations/verify.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cargo clean
6 |
7 | # verify using KLEE
8 | # this should detect an error
9 | cargo-verify --tests --verbose | tee out1 || true
10 | grep -q -F "test t1 ... ASSERT_FAILED" out1
11 |
12 | # replay input values
13 | cargo-verify --tests --replay | tee out2 || true
14 | grep -q -F "Test values: a = 1000, b = 1000" out2
15 |
--------------------------------------------------------------------------------
/demos/simple/argv/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "argv"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 |
11 | [target.'cfg(not(verify))'.dependencies]
12 | proptest = { version = "0.10" }
13 |
14 | [target.'cfg(verify)'.dependencies]
15 | propverify = { path="/home/rust-verification-tools/propverify" }
16 |
17 | [features]
18 | verifier-klee = ["propverify/verifier-klee"]
19 | verifier-crux = ["propverify/verifier-crux"]
20 | verifier-seahorn = ["propverify/verifier-seahorn"]
21 |
--------------------------------------------------------------------------------
/demos/simple/argv/src/main.rs:
--------------------------------------------------------------------------------
1 | #[cfg(not(verify))]
2 | use proptest::prelude::*;
3 | #[cfg(verify)]
4 | use propverify::prelude::*;
5 |
6 | use std::env;
7 |
8 | /// Simple test to confirm that it is possible to pass arguments
9 | /// to Rust functions when verifying them.
10 | ///
11 | /// Should pass:
12 | /// `cargo verify . -- foo`
13 | /// `cargo verify . -- foo foo`
14 | ///
15 | /// Should fail:
16 | /// `cargo verify .`
17 | /// `cargo verify . --`
18 | /// `cargo verify . -- foo bar`
19 | fn main() {
20 | println!("{} args", env::args().len());
21 | verifier::assert!(env::args().len() >= 2);
22 | for a in env::args().skip(1) {
23 | println!("{}", a);
24 | verifier::assert!(a == "foo");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demos/simple/errors/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 |
--------------------------------------------------------------------------------
/demos/simple/errors/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "errors"
3 | version = "0.1.0"
4 | authors = ["adreid"]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 |
11 | [target.'cfg(verify)'.dependencies]
12 | propverify = { path="/home/rust-verification-tools/propverify" }
13 |
14 | [target.'cfg(not(verify))'.dependencies]
15 | proptest = { version = "*" }
16 |
17 |
18 | [features]
19 | verifier-crux = ["propverify/verifier-crux"]
20 | verifier-klee = ["propverify/verifier-klee"]
21 | verifier-seahorn = ["propverify/verifier-seahorn"]
22 |
--------------------------------------------------------------------------------
/demos/simple/errors/src/main.rs:
--------------------------------------------------------------------------------
1 | /// Test detection of various types of error
2 |
3 | #[cfg(not(verify))]
4 | use proptest::prelude::*;
5 | #[cfg(verify)]
6 | use propverify::prelude::*;
7 |
8 | proptest! {
9 | // #[should_panic(expected = "overflow")]
10 | #[cfg_attr(feature="verifier-crux", crux_test)]
11 | #[cfg_attr(not(feature="verifier-crux"), test)]
12 | fn overflow_should_fail(a: u32) {
13 | // Normally, this could fail due to wraparound but we verify
14 | // with overflow checks enabled so it cannot fail.
15 | assert!(a+1 >= a);
16 | }
17 | }
18 |
19 | proptest! {
20 | // #[should_panic(expected = "index out of bounds")]
21 | #[allow(unconditional_panic)]
22 | #[cfg_attr(feature="verifier-crux", crux_test)]
23 | #[cfg_attr(not(feature="verifier-crux"), test)]
24 | fn bounds_should_fail(_a: u32) {
25 | let a: [u32; 3] = [1, 2, 3];
26 | assert_eq!(a[3], 4)
27 | }
28 | }
29 |
30 | proptest! {
31 | // #[should_panic(expected = "HELP")]
32 | #[cfg_attr(feature="verifier-crux", crux_test)]
33 | #[cfg_attr(not(feature="verifier-crux"), test)]
34 | fn panic_should_fail(_a: u32) {
35 | panic!("HELP")
36 | }
37 | }
38 |
39 | proptest! {
40 | // #[should_panic(expected = "assertion")]
41 | #[cfg_attr(feature="verifier-crux", crux_test)]
42 | #[cfg_attr(not(feature="verifier-crux"), test)]
43 | fn std_assert_should_fail(_a: u32) {
44 | std::assert!(false)
45 | }
46 | }
47 |
48 | proptest! {
49 | // #[should_panic(expected = "assertion")]
50 | #[cfg_attr(feature="verifier-crux", crux_test)]
51 | #[cfg_attr(not(feature="verifier-crux"), test)]
52 | fn prop_assert_should_fail(_a: u32) {
53 | prop_assert!(false)
54 | }
55 | }
56 |
57 | proptest! {
58 | // #[should_panic(expected = "assertion failed: `(left == right)`")]
59 | #[cfg_attr(feature="verifier-crux", crux_test)]
60 | #[cfg_attr(not(feature="verifier-crux"), test)]
61 | fn assert_eq_should_fail(_a: u32) {
62 | assert_eq!(1, 2)
63 | }
64 | }
65 |
66 | proptest! {
67 | // #[should_panic(expected = "Option::unwrap()")]
68 | #[cfg_attr(feature="verifier-crux", crux_test)]
69 | #[cfg_attr(not(feature="verifier-crux"), test)]
70 | fn unwrap_should_fail(_a: u32) {
71 | None.unwrap()
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/demos/simple/errors/verify.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cargo clean
6 |
7 | # this should detect multiple errors
8 | cargo-verify --tests --verbose | tee out || true
9 |
10 | # check for all expected errors
11 | grep -q -F "test assert_eq_should_fail ... ASSERT_FAILED" out
12 | grep -q -F "test bounds_should_fail ... OUT_OF_BOUNDS" out
13 | grep -q -F "test overflow_should_fail ... OVERFLOW" out
14 | grep -q -F "test panic_should_fail ... PANIC" out
15 | grep -q -F "test prop_assert_should_fail ... ASSERT_FAILED" out
16 | grep -q -F "test std_assert_should_fail ... ASSERT_FAILED" out
17 | grep -q -F "test unwrap_should_fail ... PANIC" out
18 |
19 | echo "Test detected all errors"
20 |
--------------------------------------------------------------------------------
/demos/simple/ffi/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ffi"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | libc = "0.2"
9 |
10 | [target.'cfg(not(verify))'.dependencies]
11 | proptest = { version = "0.10" }
12 |
13 | [target.'cfg(verify)'.dependencies]
14 | propverify = { path="/home/rust-verification-tools/propverify" }
15 |
16 | [features]
17 | verifier-klee = ["propverify/verifier-klee"]
18 | verifier-crux = ["propverify/verifier-crux"]
19 | verifier-seahorn = ["propverify/verifier-seahorn"]
20 |
21 | [build-dependencies]
22 | cc = "1.0"
23 |
--------------------------------------------------------------------------------
/demos/simple/ffi/bar.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int32_t bar_function(int32_t x) {
4 | return x+1;
5 | }
6 |
--------------------------------------------------------------------------------
/demos/simple/ffi/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | cc::Build::new().file("bar.c").compile("bar_library");
3 | }
4 |
--------------------------------------------------------------------------------
/demos/simple/ffi/src/main.rs:
--------------------------------------------------------------------------------
1 | #[cfg(not(verify))]
2 | use proptest::prelude::*;
3 | #[cfg(verify)]
4 | use propverify::prelude::*;
5 |
6 | #[link(name = "bar_library")]
7 | extern "C" {
8 | fn bar_function(x: i32) -> i32;
9 | }
10 |
11 | fn bar(x: i32) -> i32 {
12 | unsafe { bar_function(x) }
13 | }
14 |
15 | proptest! {
16 | fn main(i: i32) {
17 | prop_assert!(bar(i) != i)
18 | }
19 | }
20 |
21 | proptest! {
22 | #[test]
23 | fn inequal(x: i32) {
24 | prop_assert!(bar(x) != x)
25 | }
26 | }
27 |
28 | proptest! {
29 | #[test]
30 | #[should_panic(expected = "assertion failed")]
31 | fn greater(x: i32) {
32 | prop_assert!(bar(x) > x)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/demos/simple/klee/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "try-klee"
3 | version = "0.1.0"
4 | authors = [""]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
9 |
10 | [features]
11 | verifier-klee = ["verification-annotations/verifier-klee"]
12 |
--------------------------------------------------------------------------------
/demos/simple/klee/src/main.rs:
--------------------------------------------------------------------------------
1 | use verification_annotations::prelude::*;
2 |
3 | fn main() {
4 | let a = u32::abstract_value();
5 | let b = u32::abstract_value();
6 | verifier::assume(1 <= a && a <= 1000);
7 | verifier::assume(1 <= b && b <= 1000);
8 | if verifier::is_replay() {
9 | eprintln!("Test values: a = {}, b = {}", a, b);
10 | }
11 | let r = a * b;
12 | verifier::assert!(1 <= r && r <= 1000000);
13 | }
14 |
--------------------------------------------------------------------------------
/demos/simple/klee/verify.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | export RUSTFLAGS="-Clto -Cembed-bitcode=yes --emit=llvm-bc $RUSTFLAGS"
6 | export RUSTFLAGS="--cfg=verify $RUSTFLAGS"
7 | export RUSTFLAGS="-Warithmetic-overflow -Coverflow-checks=yes $RUSTFLAGS"
8 | # export RUSTFLAGS="-Zpanic_abort_tests $RUSTFLAGS"
9 | export RUSTFLAGS="-Cpanic=abort $RUSTFLAGS"
10 |
11 | # optional for this simple example
12 | export RUSTFLAGS="-Copt-level=1 $RUSTFLAGS"
13 | export RUSTFLAGS="-Cno-vectorize-loops -Cno-vectorize-slp $RUSTFLAGS"
14 | export RUSTFLAGS="-Ctarget-feature=-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2 $RUSTFLAGS"
15 |
16 | cargo clean
17 | cargo build --features=verifier-klee
18 |
19 | # verify using KLEE
20 | rm -rf kleeout
21 | klee --libc=klee --silent-klee-assume --output-dir=kleeout --warnings-only-to-file target/debug/deps/try_klee*.bc
22 |
23 | # view input value for first path
24 | ktest-tool kleeout/test000001.ktest
25 |
26 | # replay input values
27 | KTEST_FILE=kleeout/test000001.ktest cargo run --features=verifier-klee
28 |
--------------------------------------------------------------------------------
/demos/simple/seahorn/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "try-seahorn"
3 | version = "0.1.0"
4 | authors = [""]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
9 | # serde = { version = "1.0", features = ["derive"] }
10 |
11 | [features]
12 | # cargo-verify expects the feature `verifier-`
13 | verifier-seahorn = ["verification-annotations/verifier-seahorn"]
14 |
--------------------------------------------------------------------------------
/demos/simple/seahorn/src/main.rs:
--------------------------------------------------------------------------------
1 | use verification_annotations::prelude::*;
2 |
3 | fn main() {
4 | let a = u32::abstract_value();
5 | let b = u32::abstract_value();
6 | verifier::assume(1 <= a && a <= 1000);
7 | verifier::assume(1 <= b && b <= 1000);
8 | let r = a * b;
9 | verifier::assert!(1 <= r && r < 1000000);
10 | }
11 |
--------------------------------------------------------------------------------
/demos/simple/seahorn/verify.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -x
4 | set -e
5 |
6 | export RUSTFLAGS="-Clto -Cembed-bitcode=yes --emit=llvm-bc $RUSTFLAGS"
7 | export RUSTFLAGS="--cfg=verify $RUSTFLAGS"
8 | export RUSTFLAGS="-Warithmetic-overflow -Coverflow-checks=yes $RUSTFLAGS"
9 | export RUSTFLAGS="-Zpanic_abort_tests -Cpanic=abort $RUSTFLAGS"
10 |
11 | # optional for this simple example
12 | # export RUSTFLAGS="-Copt-level=1 $RUSTFLAGS"
13 | # export RUSTFLAGS="-Cno-vectorize-loops -Cno-vectorize-slp $RUSTFLAGS"
14 | # export RUSTFLAGS="-Ctarget-feature=-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2 $RUSTFLAGS"
15 |
16 | cargo clean
17 | cargo build --features=verifier-seahorn
18 |
19 | rvt-patch-llvm -o try_seahorn.patch.bc --seahorn -vv target/debug/deps/try_seahorn-*.bc
20 |
21 | # Find the mangled main function
22 | MAIN="$(llvm-nm-${LLVM_VERSION} --defined-only try_seahorn.patch.bc | grep main | cut -d ' ' -f3)"
23 |
24 | # verify using SeaHorn
25 | rm -rf seaout
26 | sea yama -y ${SEAHORN_VERIFY_C_COMMON_DIR}/seahorn/sea_base.yaml bpf --temp-dir=seaout --entry="${MAIN}" try_seahorn.patch.bc
27 |
28 | # To get a trace:
29 | # sea yama -y ${SEAHORN_VERIFY_C_COMMON_DIR}/seahorn/sea_cex_base.yaml bpf --temp-dir=seaout --entry="${MAIN}" try_seahorn.patch.bc
30 |
--------------------------------------------------------------------------------
/demos/simple/string/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "string"
3 | version = "0.1.0"
4 | authors = ["Shaked Flur "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | regex = "1"
11 |
12 | [target.'cfg(verify)'.dependencies]
13 | propverify = { path="/home/rust-verification-tools/propverify" }
14 | verification-annotations = { path = "/home/rust-verification-tools/verification-annotations" }
15 |
16 | [target.'cfg(not(verify))'.dependencies]
17 | proptest = { version = "*" }
18 |
19 | [features]
20 | verifier-klee = ["propverify/verifier-klee", "verification-annotations/verifier-klee"]
21 | verifier-crux = ["propverify/verifier-crux"]
22 | verifier-seahorn = ["propverify/verifier-seahorn"]
23 |
--------------------------------------------------------------------------------
/demos/simple/string/src/main.rs:
--------------------------------------------------------------------------------
1 | #[cfg(not(verify))]
2 | use proptest::prelude::*;
3 | #[cfg(verify)]
4 | use propverify::prelude::*;
5 |
6 | use regex::Regex;
7 |
8 | proptest! {
9 | #[test]
10 | // Construct an arbitrary (utf8) string from 3 bytes.
11 | // Klee can only handle a small number of bytes in this case.
12 | fn string(s in prop::string::arbitrary(3)) {
13 | let re = Regex::new(r"^a").unwrap();
14 | prop_assume!(re.is_match(&s));
15 | prop_assert!(s.starts_with('a'));
16 | }
17 | }
18 |
19 | proptest! {
20 | #[test]
21 | // Construct a (utf8) string from 100 bytes, restricted to ascii chars.
22 | // Klee can handle much more bytes this way.
23 | fn ascii_string(s in prop::string::arbitrary_ascii(100)) {
24 | let re = Regex::new(r"^a").unwrap();
25 | prop_assume!(re.is_match(&s));
26 | prop_assert!(s.starts_with('a'));
27 | }
28 | }
29 |
30 | proptest! {
31 | #[test]
32 | #[should_panic]
33 | fn string_add(s1 in prop::string::arbitrary_ascii(200), s2 in prop::string::arbitrary_ascii(200)) {
34 | let s = s1 + &s2;
35 | let s: String = s.chars().rev().collect();
36 | prop_assert!(s.len() == 200);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demos/simple/vectest/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "vectest"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | [target.'cfg(not(verify))'.dependencies]
8 | proptest = { version = "0.10" }
9 |
10 | [target.'cfg(verify)'.dependencies]
11 | propverify = { path="/home/rust-verification-tools/propverify" }
12 |
13 | [features]
14 | verifier-klee = ["propverify/verifier-klee"]
15 | verifier-crux = ["propverify/verifier-crux"]
16 | verifier-seahorn = ["propverify/verifier-seahorn"]
17 |
--------------------------------------------------------------------------------
/demos/simple/vectest/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::arch::x86_64::*;
2 | use std::mem::transmute;
3 |
4 | unsafe fn test_mm_cmpeq_epi8(x: i8) {
5 | let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
6 | let b = _mm_setr_epi8(15, 14, x, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
7 | let r = _mm_cmpeq_epi8(a, b);
8 | assert_eq_m128i(
9 | r,
10 | _mm_setr_epi8(0, 0, 0xFFu8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
11 | );
12 | }
13 |
14 | unsafe fn test_mm_movemask_epi8(x: i8) {
15 | let a = _mm_set1_epi8(x);
16 | let r = _mm_movemask_epi8(a);
17 | println!("movemask({:?}) = {}", a, r);
18 | }
19 |
20 | unsafe fn test_mm_xor_si128() {
21 | let a = _mm_set1_epi8(5);
22 | let b = _mm_set1_epi8(3);
23 | let r = _mm_xor_si128(a, b);
24 | assert_eq_m128i(r, _mm_set1_epi8(6));
25 | }
26 |
27 | pub unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) {
28 | assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b))
29 | }
30 |
31 | fn main() {
32 | println!("Hello, world!");
33 | unsafe { test_mm_cmpeq_epi8(2) };
34 | unsafe { test_mm_cmpeq_epi8(2) };
35 | unsafe { test_mm_xor_si128() };
36 | for i in -3..3 {
37 | unsafe { test_mm_movemask_epi8(i) };
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/docker/README.md:
--------------------------------------------------------------------------------
1 | # Docker images
2 |
3 | These scripts provide a convenient, portable way to build the Rust verification tools and their dependencies.
4 |
5 | At present, only the KLEE backend is supported.
6 |
7 | Todo: at the moment, the scripts use 'sudo' when invoking docker.
8 | This is necessary on some platforms but not necessary on other platforms.
9 | It is not clear whether there is any value in avoiding the use of sudo.
10 |
11 |
12 | ## Building docker images
13 |
14 | The script `docker/build` builds the following images
15 |
16 | - `rvt_base:latest` contains Ubuntu and standard Ubuntu packages
17 | - `rvt_rustc:latest` adds the Rust compiler
18 | - `rvt_minisat:latest` adds the MiniSat solver
19 | - `rvt_stp:latest` adds the STP solver
20 | - `rvt_klee:latest` adds the KLEE symbolic execution engine
21 | - `rvt:latest` adds a snapshot of the Rust verification tools repo
22 |
23 | In practice, the only image that is useful is `rvt`.
24 | The other images exist only to make it faster to rebuild rvt
25 | It takes several hours to build the `rvt_rustc` image.
26 |
27 | The `docker/build` script should be invoked in the top directory of `rust-verification-tools`.
28 | The script will invoke `sudo` so you may be asked for your password.
29 |
30 | Building the images creates an unprivileged user with the same username, uid and gid as the user that
31 | ran `docker/build`.
32 |
33 | No attempt has been made to reduce the size of the images – they total around 13GB.
34 |
35 |
36 | ## Using docker images
37 |
38 | The `rvt` image can be invoked using the script `docker/run` script.
39 | This script:
40 |
41 | - Mounts the current directory as read/write so that `rvt` can access
42 | any files in the current directory or its subdirectories.
43 | Parent directories are not accessible.
44 |
45 | - The image will run with the permissions of the user that created the image.
46 | It is expected that this will be the current user.
47 |
48 | - The PATH contains the Rust compiler, LLVM, Cargo and the Rust-verification-tools script `cargo-verify`.
49 |
50 | - The `rvt` image contains a copy of `rust-verification-tools` in `/home/rust-verification-tools`.
51 |
52 | The dependencies in `Cargo.toml` files typically contain lines like
53 |
54 | ```
55 | verification-annotations = { path="/home/rust-verification-tools/verification-annotations" }
56 | propverify = { path="/home/rust-verification-tools/propverify" }
57 | ```
58 |
59 | - If any arguments are provided, they will be treated as commands to run in `rvt`.
60 | Otherwise, the `bash` shell will be run and `exit` can be used to exit docker.
61 |
62 |
--------------------------------------------------------------------------------
/docker/base/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG UBUNTU_VERSION
2 | FROM ubuntu:${UBUNTU_VERSION}
3 |
4 | # Install Debian and Python dependencies
5 | ARG DEBIAN_FRONTEND=noninteractive
6 | RUN apt-get --yes update \
7 | && apt-get install --no-install-recommends --yes \
8 | bison \
9 | build-essential \
10 | clang-10 \
11 | clang-format-10 \
12 | clang-tools-10 \
13 | clang-11 \
14 | clang-format-11 \
15 | clang-tools-11 \
16 | gcc-multilib \
17 | g++-7-multilib \
18 | cmake \
19 | curl \
20 | doxygen \
21 | expect \
22 | flex \
23 | git \
24 | libboost-all-dev \
25 | libcap-dev \
26 | libffi-dev \
27 | libgoogle-perftools-dev \
28 | libncurses5-dev \
29 | libsqlite3-dev \
30 | libssl-dev \
31 | libtcmalloc-minimal4 \
32 | lib32stdc++-7-dev \
33 | libgmp-dev \
34 | libgmpxx4ldbl \
35 | lld-10 \
36 | lld-11 \
37 | llvm-10 \
38 | llvm-10-dev \
39 | llvm-11 \
40 | llvm-11-dev \
41 | ncurses-doc \
42 | ninja-build \
43 | perl \
44 | pkg-config \
45 | python \
46 | python3 \
47 | python3-minimal \
48 | python3-pip \
49 | subversion \
50 | sudo \
51 | unzip \
52 | wget \
53 | # Cleanup
54 | && apt-get clean \
55 | # Install Python packages
56 | && pip3 install --no-cache-dir setuptools \
57 | && pip3 install --no-cache-dir \
58 | argparse \
59 | colored \
60 | lit \
61 | pyyaml \
62 | tabulate \
63 | termcolor \
64 | toml \
65 | wllvm
66 |
67 |
68 | # Placeholder args that are expected to be passed in at image build time.
69 | # See https://code.visualstudio.com/docs/remote/containers-advanced#_creating-a-nonroot-user
70 | ARG USERNAME=user-name-goes-here
71 | ARG USER_UID=1000
72 | ARG USER_GID=${USER_UID}
73 | ENV USER_HOME=/home/${USERNAME}
74 |
75 | # Create the specified user and group and add them to sudoers list
76 | #
77 | # Ignore errors if the user or group already exist (it should only happen if the image is being
78 | # built as root, which happens on GCB).
79 | RUN (groupadd --gid=${USER_GID} ${USERNAME} || true) \
80 | && (useradd --shell=/bin/bash --uid=${USER_UID} --gid=${USER_GID} --create-home ${USERNAME} || true) \
81 | && echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
82 |
83 |
--------------------------------------------------------------------------------
/docker/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo To build LLVM11 version, use 'env LLVM11=yes docker/build'
4 |
5 | set -e
6 |
7 | # Build each image
8 | #
9 | # Note that each image is built in a subdirectory to avoid breaking
10 | # Docker's caching.
11 | #
12 | # Note too that all these commands except the final rvt command
13 | # make snapshots of git repos.
14 | # Images should be deleted and rebuilt to get any changes from the
15 | # git repos.
16 |
17 | (cd docker/base && ../mkimage rvt_base Dockerfile)
18 | (cd docker/solvers && ../mkimage rvt_solvers Dockerfile)
19 | (cd docker/klee && ../mkimage rvt_klee Dockerfile)
20 | (cd docker/seahorn && ../mkimage rvt_seahorn Dockerfile)
21 | (cd docker/smack && ../mkimage rvt_smack Dockerfile)
22 |
23 | # This does not run in a subdirectory so it will copy everything over.
24 | # This is really unfortunate but it allows us to run docker/init
25 | # to prebuild all our scripts/libraries.
26 | docker/mkimage rvt docker/rvt/Dockerfile
27 |
28 | # Optional: verification profiling support
29 | # Note that this creates a VERY LARGE image including X11, kcachegrind and lots more
30 | (cd docker/rust2calltree && ../mkimage rvt_r2ct Dockerfile)
31 |
--------------------------------------------------------------------------------
/docker/init:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 |
3 | set -e
4 |
5 | # Build libraries
6 | make -C ${RVT_DIR}/runtime TGT=klee
7 | make -C ${RVT_DIR}/runtime TGT=seahorn
8 | make -C ${RVT_DIR}/runtime TGT=smack
9 | make -C ${RVT_DIR}/simd_emulation
10 |
11 | # Build tools
12 | mkdir -p ${USER_HOME}/bin
13 | cargo +nightly install --root=${USER_HOME} --path=${RVT_DIR}/rust2calltree
14 | cargo +nightly install --features=llvm${LLVM_VERSION} --root=${USER_HOME} --path=${RVT_DIR}/rvt-patch-llvm
15 | cargo +nightly install --root=${USER_HOME} --path=${RVT_DIR}/cargo-verify
16 |
--------------------------------------------------------------------------------
/docker/klee/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_KLEE
2 | FROM ${FROM_IMAGE_FOR_KLEE}
3 |
4 | ARG USERNAME
5 |
6 | USER root
7 | WORKDIR ${USER_HOME}
8 | COPY build_googletest .
9 | COPY build_klee .
10 | RUN chown ${USERNAME} -R build_googletest build_klee
11 |
12 | USER ${USERNAME}
13 | WORKDIR ${USER_HOME}
14 |
15 | ARG GTEST_VERSION
16 | ENV GTEST_DIR=${USER_HOME}/googletest-release-${GTEST_VERSION}
17 | RUN sh build_googletest
18 |
19 | ARG UCLIBC_VERSION
20 |
21 | ARG LLVM_VERSION
22 | ENV LLVM_VERSION=${LLVM_VERSION}
23 |
24 | ARG KLEE_VERSION
25 | RUN sh build_klee
26 |
--------------------------------------------------------------------------------
/docker/klee/build_googletest:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | curl -OL https://github.com/google/googletest/archive/release-${GTEST_VERSION}.zip
6 | unzip -q release-${GTEST_VERSION}.zip
7 | rm release-${GTEST_VERSION}.zip
8 |
--------------------------------------------------------------------------------
/docker/klee/build_klee:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | readonly LLVMCC=`which clang-${LLVM_VERSION}`
6 | readonly LLVMCXX=`which clang++-${LLVM_VERSION}`
7 | readonly LLVM_CONFIG=`which llvm-config-${LLVM_VERSION}`
8 |
9 | git clone https://github.com/klee/klee-uclibc.git
10 | cd klee-uclibc
11 | git checkout ${UCLIBC_VERSION}
12 | readonly UCLIBC_DIR=`pwd`
13 | ./configure --make-llvm-lib --with-cc="${LLVMCC}" --with-llvm-config="${LLVM_CONFIG}"
14 | make -j 4
15 | cd ..
16 |
17 | git clone --no-checkout https://github.com/klee/klee.git
18 | cd klee
19 | git checkout ${KLEE_VERSION}
20 |
21 | mkdir build
22 | cd build
23 | cmake \
24 | -DCMAKE_INSTALL_PREFIX=/usr \
25 | -DENABLE_SOLVER_STP=ON \
26 | -DENABLE_SOLVER_Z3=ON \
27 | -DENABLE_KLEE_UCLIBC=ON \
28 | -DENABLE_POSIX_RUNTIME=ON \
29 | -DKLEE_UCLIBC_PATH="${UCLIBC_DIR}" \
30 | -DLLVMCC="${LLVMCC}" \
31 | -DLLVMCXX="${LLVMCXX}" \
32 | -DLLVM_CONFIG_BINARY="${LLVM_CONFIG}" \
33 | -DENABLE_UNIT_TESTS=ON \
34 | -DGTEST_SRC_DIR=${GTEST_DIR} \
35 | ..
36 | make -j 4
37 | # make check
38 | sudo make install
39 | make clean
40 |
--------------------------------------------------------------------------------
/docker/mkimage:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source $(dirname "$(realpath -s "$0")")/sudo_if_needed.bash
4 |
5 | readonly DOCKER_IMAGE_NAME="$1"
6 | readonly DOCKER_FILE="$2"
7 | readonly DOCKER_VERSION="latest"
8 |
9 | echo Making docker image ${DOCKER_IMAGE_NAME}:${DOCKER_VERSION} using ${DOCKER_FILE}
10 |
11 | # The default user for a Docker container has uid 0 (root). To avoid creating
12 | # root-owned files in the build directory we tell Docker to use the current user
13 | # ID, if known.
14 | # See
15 | # https://github.com/googleapis/google-cloud-cpp/blob/a186208b79d900b4ec71c6f9df3acf7638f01dc6/ci/kokoro/docker/build.sh#L147-L152
16 | readonly DOCKER_UID="${UID:-0}"
17 | readonly DOCKER_GID="$(id -g)"
18 | readonly DOCKER_USER="${USER:-root}"
19 |
20 | readonly FROM_IMAGE_FOR_SOLVERS=${FROM_IMAGE_FOR_SOLVERS:-rvt_base:latest}
21 | readonly FROM_IMAGE_FOR_KLEE=${FROM_IMAGE_FOR_KLEE:-rvt_solvers:latest}
22 | readonly FROM_IMAGE_FOR_SEAHORN=${FROM_IMAGE_FOR_SEAHORN:-rvt_klee:latest}
23 | readonly FROM_IMAGE_FOR_SMACK=${FROM_IMAGE_FOR_SMACK:-rvt_seahorn:latest}
24 | readonly FROM_IMAGE_FOR_RVT=${FROM_IMAGE_FOR_RVT:-rvt_smack:latest}
25 | readonly FROM_IMAGE_FOR_RVT_R2CT=${FROM_IMAGE_FOR_RVT_R2CT:-rvt:latest}
26 |
27 | if [ -v LLVM11 ]; then
28 | # Version used in Rust for Linux
29 | RUSTC_VERSION=nightly-2021-02-20
30 | LLVM_VERSION=11
31 | KLEE_VERSION="abdb0b650b8fce419dc5695e037557708f374021"
32 | else
33 | # Last version based on LLVM-10
34 | RUSTC_VERSION=nightly-2020-08-03
35 | LLVM_VERSION=10
36 | KLEE_VERSION="c51ffcd377097ee80ec9b0d6f07f8ea583a5aa1d"
37 | fi
38 |
39 | sudo_if_needed docker build \
40 | --file=${DOCKER_FILE} \
41 | --cache-from="${DOCKER_IMAGE_NAME}:${DOCKER_VERSION}" \
42 | --tag="${DOCKER_IMAGE_NAME}:${DOCKER_VERSION}" \
43 | --build-arg=FROM_IMAGE_FOR_SOLVERS="$FROM_IMAGE_FOR_SOLVERS" \
44 | --build-arg=FROM_IMAGE_FOR_KLEE="$FROM_IMAGE_FOR_KLEE" \
45 | --build-arg=FROM_IMAGE_FOR_SEAHORN="$FROM_IMAGE_FOR_SEAHORN" \
46 | --build-arg=FROM_IMAGE_FOR_SMACK="$FROM_IMAGE_FOR_SMACK" \
47 | --build-arg=FROM_IMAGE_FOR_RVT="$FROM_IMAGE_FOR_RVT" \
48 | --build-arg=FROM_IMAGE_FOR_RVT_R2CT="$FROM_IMAGE_FOR_RVT_R2CT" \
49 | --build-arg=USERNAME="$DOCKER_USER" \
50 | --build-arg=USER_UID="$DOCKER_UID" \
51 | --build-arg=USER_GID="$DOCKER_GID" \
52 | --build-arg=UBUNTU_VERSION="20.04" \
53 | --build-arg=GTEST_VERSION="1.7.0" \
54 | --build-arg=LLVM_VERSION="${LLVM_VERSION}" \
55 | --build-arg=KLEE_VERSION="${KLEE_VERSION}" \
56 | --build-arg=MINISAT_VERSION="37158a35c62d448b3feccfa83006266e12e5acb7" \
57 | --build-arg=RUSTC_VERSION="${RUSTC_VERSION}" \
58 | --build-arg=STP_VERSION="2.3.3" \
59 | --build-arg=SEAHORN_VERIFY_C_COMMON_VERSION="70129bf47c421d8283785a8fb13cdb216424ef91" \
60 | --build-arg=SEAHORN_VERSION="ccdc529f81a02e9236ffa00ff57eef4487f0fc9a" \
61 | --build-arg=UCLIBC_VERSION="klee_uclibc_v1.2" \
62 | --build-arg=YICES_VERSION="2.6.2" \
63 | --build-arg=Z3_VERSION="4.8.7" \
64 | . 1>&2
65 |
66 | # sea nov 30 "2e7239d8d2d7be21e64956aa83d936a773e18e32"
67 | # common "8dadb385483984cde4d3a24a61629621e12f6437"
68 |
--------------------------------------------------------------------------------
/docker/run:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source $(dirname "$(realpath -s "$0")")/sudo_if_needed.bash
4 |
5 | readonly RVT_SRC=$(dirname "$(realpath -s "$0")")/..
6 | readonly RVT_DST=/home/rust-verification-tools
7 |
8 | readonly MOUNT_PWD="type=bind,source=${PWD},target=${PWD}"
9 | readonly MOUNT_RVT="type=bind,source=${RVT_SRC},target=${RVT_DST}"
10 |
11 | # based on https://dzone.com/articles/docker-x11-client-via-ssh
12 | readonly X11="--net=host --env=DISPLAY --volume=$HOME/.Xauthority:/home/$USER/.Xauthority:rw"
13 |
14 | sudo_if_needed docker run --rm --mount ${MOUNT_RVT} --mount ${MOUNT_PWD} --workdir ${PWD} ${X11} -it rvt_r2ct:latest "$@"
15 |
--------------------------------------------------------------------------------
/docker/rust2calltree/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_RVT_R2CT
2 | FROM ${FROM_IMAGE_FOR_RVT_R2CT}
3 |
4 | # Placeholder args that are expected to be passed in at image build time.
5 | # See https://code.visualstudio.com/docs/remote/containers-advanced#_creating-a-nonroot-user
6 | ARG USERNAME=user-name-goes-here
7 | ARG USER_UID=1000
8 | ARG USER_GID=${USER_UID}
9 |
10 | # Install more packages
11 | # We don't install this in base because they are HUGE and optional
12 | USER root
13 | RUN apt-get --yes update \
14 | && apt-get install --no-install-recommends --yes \
15 | dbus-x11 \
16 | kcachegrind \
17 | # Cleanup
18 | && apt-get clean
19 |
20 | # Switch back to unprivileged user
21 | USER ${USERNAME}
22 | WORKDIR ${USER_HOME}
23 | ENV USER=${USERNAME}
24 |
--------------------------------------------------------------------------------
/docker/rvt/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_RVT
2 | FROM ${FROM_IMAGE_FOR_RVT}
3 |
4 | # Placeholder args that are expected to be passed in at image build time.
5 | # See https://code.visualstudio.com/docs/remote/containers-advanced#_creating-a-nonroot-user
6 | ARG USERNAME=user-name-goes-here
7 | ARG USER_UID=1000
8 | ARG USER_GID=${USER_UID}
9 |
10 | # Switch to USERNAME and install tools / set environment
11 | USER ${USERNAME}
12 | WORKDIR ${USER_HOME}
13 | ENV USER=${USERNAME}
14 |
15 | ENV PATH="${PATH}:${USER_HOME}/bin"
16 | ENV PATH="${PATH}:${USER_HOME}/.cargo/bin"
17 |
18 | # Install rustup
19 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
20 |
21 | # Install the nightly toolchain - we use it to build some of our tools.
22 | # We do not set it as the default though because we want to use the
23 | # version of rustc and lib{core,std} that we built before
24 | # and, in particular, we have to use a version of rustc that uses LLVM-10.
25 | RUN rustup toolchain install nightly
26 |
27 | # Version of rustc that our tools support
28 | # This is the default
29 | ARG RUSTC_VERSION
30 | ENV RUSTC_VERSION=${RUSTC_VERSION}
31 | RUN echo Installing ${RUSTC_VERSION}
32 | RUN rustup toolchain install ${RUSTC_VERSION} --profile=minimal
33 | RUN rustup default ${RUSTC_VERSION}
34 |
35 | # Prebuild all the tools and libraries
36 | # Note that we can't mount RVT_DIR while we do this - so we have to make
37 | # a copy and build from there. (Which is pretty hacky)
38 | ENV RVT_DIR=${USER_HOME}/rvt_dir
39 | RUN mkdir ${RVT_DIR}
40 | COPY --chown=${USER_UID}:${USER_GID} . ${RVT_DIR}
41 | WORKDIR ${RVT_DIR}
42 | RUN ${RVT_DIR}/docker/init
43 | RUN rm -r ${RVT_DIR}
44 |
45 | # Directory we mount RVT repo in
46 | # Note that this overrides value we just built
47 | ENV RVT_DIR=/home/rust-verification-tools
48 |
49 | ENV PATH="${PATH}:${RVT_DIR}/scripts"
50 | ENV PATH="${PATH}:${RVT_DIR}/scripts/bin"
51 |
52 | # Create a bashrc file
53 | RUN echo "export PATH=\"${PATH}\":\${PATH}" >> ${USER_HOME}/.bashrc \
54 | && echo "ulimit -c0" >> ${USER_HOME}/.bashrc
55 |
--------------------------------------------------------------------------------
/docker/seahorn/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_SEAHORN
2 | FROM ${FROM_IMAGE_FOR_SEAHORN}
3 |
4 | USER ${USERNAME}
5 | WORKDIR ${USER_HOME}
6 |
7 | ARG SEAHORN_VERIFY_C_COMMON_VERSION
8 | ARG SEAHORN_VERSION
9 | ARG LLVM_VERSION
10 | ARG YICES_VERSION
11 |
12 | # cargo-verify relies on this variable to find the yaml files
13 | ENV SEAHORN_VERIFY_C_COMMON_DIR=${USER_HOME}/verify-c-common
14 |
15 | RUN git clone --no-checkout https://github.com/seahorn/verify-c-common.git ${SEAHORN_VERIFY_C_COMMON_DIR} \
16 | && cd ${SEAHORN_VERIFY_C_COMMON_DIR} \
17 | && git checkout ${SEAHORN_VERIFY_C_COMMON_VERSION}
18 |
19 | ENV SEAHORN_DIR=${USER_HOME}/seahorn
20 |
21 | RUN git clone --no-checkout https://github.com/seahorn/seahorn.git ${SEAHORN_DIR} \
22 | && cd ${SEAHORN_DIR} \
23 | && git checkout ${SEAHORN_VERSION}
24 |
25 | # Configure, build and install SeaHorn
26 | # Afterwards, clean up large files but not configuration files
27 | # so that RVT developers can easily tweak the configuration and rebuild.
28 | RUN mkdir ${SEAHORN_DIR}/build \
29 | && cd ${SEAHORN_DIR}/build \
30 | && cmake \
31 | # -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
32 | -DCMAKE_INSTALL_PREFIX=run \
33 | # -DCMAKE_BUILD_TYPE="Debug" \
34 | -DCMAKE_BUILD_TYPE="Release" \
35 | -DCMAKE_CXX_COMPILER="clang++-${LLVM_VERSION}" \
36 | -DCMAKE_C_COMPILER="clang-${LLVM_VERSION}" \
37 | -DZ3_ROOT=${Z3_DIR} \
38 | -DYICES2_HOME=${YICES_DIR} \
39 | -DSEA_ENABLE_LLD="ON" \
40 | -GNinja \
41 | -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
42 | -DLLVM_DIR=/usr/lib/llvm-${LLVM_VERSION}/lib/cmake/llvm \
43 | .. \
44 | && cmake --build . -j4 --target extra \
45 | && cmake --build . -j4 --target crab \
46 | && cmake .. \
47 | && sudo cmake --build . -j4 --target install \
48 | && sudo cmake --build . --target clean
49 |
50 | ENV PATH="${SEAHORN_DIR}/build/run/bin:$PATH"
51 |
--------------------------------------------------------------------------------
/docker/smack/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_SMACK
2 | FROM ${FROM_IMAGE_FOR_SMACK}
3 |
4 | USER root
5 | RUN apt-get update && \
6 | apt-get -y install \
7 | software-properties-common \
8 | wget \
9 | sudo \
10 | g++
11 |
12 | # get repo
13 | USER ${USERNAME}
14 | WORKDIR ${USER_HOME}
15 |
16 | ENV SMACK_DIR=${USER_HOME}/smack
17 |
18 | RUN git clone --no-checkout https://github.com/smackers/smack.git ${SMACK_DIR} \
19 | && cd ${SMACK_DIR} \
20 | && git checkout develop
21 |
22 | # build and install smack
23 |
24 | ENV INSTALL_Z3=0
25 | ENV TEST_SMACK=0
26 | ENV INSTALL_RUST=0
27 |
28 | RUN cd ${SMACK_DIR} && bin/build.sh --prefix ${SMACK_DIR}/smack-install
29 |
30 | RUN echo "source ${USER_HOME}/smack.environment" >> ${USER_HOME}/.bashrc
31 |
--------------------------------------------------------------------------------
/docker/solvers/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG FROM_IMAGE_FOR_SOLVERS
2 | FROM ${FROM_IMAGE_FOR_SOLVERS}
3 |
4 | ARG USERNAME
5 | USER ${USERNAME}
6 |
7 | # Install minisat solver
8 |
9 | RUN mkdir ${USER_HOME}/minisat
10 | WORKDIR ${USER_HOME}/minisat
11 |
12 | ARG MINISAT_VERSION
13 | RUN git clone --no-checkout https://github.com/stp/minisat.git \
14 | && cd minisat \
15 | && git checkout ${MINISAT_VERSION} \
16 | && git submodule init \
17 | && git submodule update \
18 | && mkdir build \
19 | && cd build \
20 | && cmake .. \
21 | && make -j4 \
22 | && sudo make install \
23 | && make clean
24 |
25 | # Install stp solver
26 |
27 | RUN mkdir ${USER_HOME}/stp
28 | WORKDIR ${USER_HOME}/stp
29 |
30 | ARG STP_VERSION
31 | RUN git clone --no-checkout https://github.com/stp/stp.git \
32 | && cd stp \
33 | && git checkout tags/${STP_VERSION} \
34 | && mkdir build \
35 | && cd build \
36 | && cmake .. \
37 | && make -j4 \
38 | && sudo make install \
39 | && make clean
40 |
41 | # Install yices solver
42 |
43 | RUN mkdir ${USER_HOME}/yices
44 | WORKDIR ${USER_HOME}/yices
45 |
46 | ARG YICES_VERSION
47 | RUN curl --location https://yices.csl.sri.com/releases/${YICES_VERSION}/yices-${YICES_VERSION}-x86_64-pc-linux-gnu-static-gmp.tar.gz > yices.tgz \
48 | && tar xf yices.tgz \
49 | && rm yices.tgz \
50 | && cd "yices-${YICES_VERSION}" \
51 | && sudo ./install-yices \
52 | && cd .. \
53 | && rm -r "yices-${YICES_VERSION}"
54 |
55 | ENV YICES_DIR=${USER_HOME}/yices/yices-${YICES_VERSION}
56 |
57 | # Install the binary version of Z3.
58 | # (Changing this to build from source would be fine - but slow)
59 | #
60 | # The Ubuntu version is a little out of date but that doesn't seem to cause any problems
61 |
62 | RUN mkdir ${USER_HOME}/z3
63 | WORKDIR ${USER_HOME}/z3
64 | ARG Z3_VERSION
65 | RUN curl --location https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-ubuntu-16.04.zip > z3.zip \
66 | && unzip -q z3.zip \
67 | && rm z3.zip
68 |
69 | ENV Z3_DIR=${USER_HOME}/z3/z3-${Z3_VERSION}-x64-ubuntu-16.04
70 |
--------------------------------------------------------------------------------
/docker/sudo_if_needed.bash:
--------------------------------------------------------------------------------
1 | # import this library with:
2 | # source $(dirname "$(realpath -s "$0")")/sudo_if_needed.bash
3 |
4 | function sudo_if_needed() {
5 | if [[ -w /var/run/docker.sock ]]; then
6 | "$@"
7 | else
8 | echo "Running docker with sudo because you don't have write access to the docker socket."
9 | echo "Add yourself to the docker group to avoid the need for this in future."
10 | sudo "$@"
11 | fi
12 | }
13 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | gem "github-pages", "~> 212", group: :jekyll_plugins
3 | gem "minima", "~> 2.5"
4 |
--------------------------------------------------------------------------------
/docs/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | activesupport (6.0.3.5)
5 | concurrent-ruby (~> 1.0, >= 1.0.2)
6 | i18n (>= 0.7, < 2)
7 | minitest (~> 5.1)
8 | tzinfo (~> 1.1)
9 | zeitwerk (~> 2.2, >= 2.2.2)
10 | addressable (2.7.0)
11 | public_suffix (>= 2.0.2, < 5.0)
12 | coffee-script (2.4.1)
13 | coffee-script-source
14 | execjs
15 | coffee-script-source (1.11.1)
16 | colorator (1.1.0)
17 | commonmarker (0.17.13)
18 | ruby-enum (~> 0.5)
19 | concurrent-ruby (1.1.8)
20 | dnsruby (1.61.5)
21 | simpleidn (~> 0.1)
22 | em-websocket (0.5.2)
23 | eventmachine (>= 0.12.9)
24 | http_parser.rb (~> 0.6.0)
25 | ethon (0.12.0)
26 | ffi (>= 1.3.0)
27 | eventmachine (1.2.7)
28 | execjs (2.7.0)
29 | faraday (1.3.0)
30 | faraday-net_http (~> 1.0)
31 | multipart-post (>= 1.2, < 3)
32 | ruby2_keywords
33 | faraday-net_http (1.0.1)
34 | ffi (1.15.0)
35 | forwardable-extended (2.6.0)
36 | gemoji (3.0.1)
37 | github-pages (212)
38 | github-pages-health-check (= 1.17.0)
39 | jekyll (= 3.9.0)
40 | jekyll-avatar (= 0.7.0)
41 | jekyll-coffeescript (= 1.1.1)
42 | jekyll-commonmark-ghpages (= 0.1.6)
43 | jekyll-default-layout (= 0.1.4)
44 | jekyll-feed (= 0.15.1)
45 | jekyll-gist (= 1.5.0)
46 | jekyll-github-metadata (= 2.13.0)
47 | jekyll-mentions (= 1.6.0)
48 | jekyll-optional-front-matter (= 0.3.2)
49 | jekyll-paginate (= 1.1.0)
50 | jekyll-readme-index (= 0.3.0)
51 | jekyll-redirect-from (= 0.16.0)
52 | jekyll-relative-links (= 0.6.1)
53 | jekyll-remote-theme (= 0.4.2)
54 | jekyll-sass-converter (= 1.5.2)
55 | jekyll-seo-tag (= 2.7.1)
56 | jekyll-sitemap (= 1.4.0)
57 | jekyll-swiss (= 1.0.0)
58 | jekyll-theme-architect (= 0.1.1)
59 | jekyll-theme-cayman (= 0.1.1)
60 | jekyll-theme-dinky (= 0.1.1)
61 | jekyll-theme-hacker (= 0.1.2)
62 | jekyll-theme-leap-day (= 0.1.1)
63 | jekyll-theme-merlot (= 0.1.1)
64 | jekyll-theme-midnight (= 0.1.1)
65 | jekyll-theme-minimal (= 0.1.1)
66 | jekyll-theme-modernist (= 0.1.1)
67 | jekyll-theme-primer (= 0.5.4)
68 | jekyll-theme-slate (= 0.1.1)
69 | jekyll-theme-tactile (= 0.1.1)
70 | jekyll-theme-time-machine (= 0.1.1)
71 | jekyll-titles-from-headings (= 0.5.3)
72 | jemoji (= 0.12.0)
73 | kramdown (= 2.3.0)
74 | kramdown-parser-gfm (= 1.1.0)
75 | liquid (= 4.0.3)
76 | mercenary (~> 0.3)
77 | minima (= 2.5.1)
78 | nokogiri (>= 1.10.4, < 2.0)
79 | rouge (= 3.26.0)
80 | terminal-table (~> 1.4)
81 | github-pages-health-check (1.17.0)
82 | addressable (~> 2.3)
83 | dnsruby (~> 1.60)
84 | octokit (~> 4.0)
85 | public_suffix (>= 2.0.2, < 5.0)
86 | typhoeus (~> 1.3)
87 | html-pipeline (2.14.0)
88 | activesupport (>= 2)
89 | nokogiri (>= 1.4)
90 | http_parser.rb (0.6.0)
91 | i18n (0.9.5)
92 | concurrent-ruby (~> 1.0)
93 | jekyll (3.9.0)
94 | addressable (~> 2.4)
95 | colorator (~> 1.0)
96 | em-websocket (~> 0.5)
97 | i18n (~> 0.7)
98 | jekyll-sass-converter (~> 1.0)
99 | jekyll-watch (~> 2.0)
100 | kramdown (>= 1.17, < 3)
101 | liquid (~> 4.0)
102 | mercenary (~> 0.3.3)
103 | pathutil (~> 0.9)
104 | rouge (>= 1.7, < 4)
105 | safe_yaml (~> 1.0)
106 | jekyll-avatar (0.7.0)
107 | jekyll (>= 3.0, < 5.0)
108 | jekyll-coffeescript (1.1.1)
109 | coffee-script (~> 2.2)
110 | coffee-script-source (~> 1.11.1)
111 | jekyll-commonmark (1.3.1)
112 | commonmarker (~> 0.14)
113 | jekyll (>= 3.7, < 5.0)
114 | jekyll-commonmark-ghpages (0.1.6)
115 | commonmarker (~> 0.17.6)
116 | jekyll-commonmark (~> 1.2)
117 | rouge (>= 2.0, < 4.0)
118 | jekyll-default-layout (0.1.4)
119 | jekyll (~> 3.0)
120 | jekyll-feed (0.15.1)
121 | jekyll (>= 3.7, < 5.0)
122 | jekyll-gist (1.5.0)
123 | octokit (~> 4.2)
124 | jekyll-github-metadata (2.13.0)
125 | jekyll (>= 3.4, < 5.0)
126 | octokit (~> 4.0, != 4.4.0)
127 | jekyll-mentions (1.6.0)
128 | html-pipeline (~> 2.3)
129 | jekyll (>= 3.7, < 5.0)
130 | jekyll-optional-front-matter (0.3.2)
131 | jekyll (>= 3.0, < 5.0)
132 | jekyll-paginate (1.1.0)
133 | jekyll-readme-index (0.3.0)
134 | jekyll (>= 3.0, < 5.0)
135 | jekyll-redirect-from (0.16.0)
136 | jekyll (>= 3.3, < 5.0)
137 | jekyll-relative-links (0.6.1)
138 | jekyll (>= 3.3, < 5.0)
139 | jekyll-remote-theme (0.4.2)
140 | addressable (~> 2.0)
141 | jekyll (>= 3.5, < 5.0)
142 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
143 | rubyzip (>= 1.3.0, < 3.0)
144 | jekyll-sass-converter (1.5.2)
145 | sass (~> 3.4)
146 | jekyll-seo-tag (2.7.1)
147 | jekyll (>= 3.8, < 5.0)
148 | jekyll-sitemap (1.4.0)
149 | jekyll (>= 3.7, < 5.0)
150 | jekyll-swiss (1.0.0)
151 | jekyll-theme-architect (0.1.1)
152 | jekyll (~> 3.5)
153 | jekyll-seo-tag (~> 2.0)
154 | jekyll-theme-cayman (0.1.1)
155 | jekyll (~> 3.5)
156 | jekyll-seo-tag (~> 2.0)
157 | jekyll-theme-dinky (0.1.1)
158 | jekyll (~> 3.5)
159 | jekyll-seo-tag (~> 2.0)
160 | jekyll-theme-hacker (0.1.2)
161 | jekyll (> 3.5, < 5.0)
162 | jekyll-seo-tag (~> 2.0)
163 | jekyll-theme-leap-day (0.1.1)
164 | jekyll (~> 3.5)
165 | jekyll-seo-tag (~> 2.0)
166 | jekyll-theme-merlot (0.1.1)
167 | jekyll (~> 3.5)
168 | jekyll-seo-tag (~> 2.0)
169 | jekyll-theme-midnight (0.1.1)
170 | jekyll (~> 3.5)
171 | jekyll-seo-tag (~> 2.0)
172 | jekyll-theme-minimal (0.1.1)
173 | jekyll (~> 3.5)
174 | jekyll-seo-tag (~> 2.0)
175 | jekyll-theme-modernist (0.1.1)
176 | jekyll (~> 3.5)
177 | jekyll-seo-tag (~> 2.0)
178 | jekyll-theme-primer (0.5.4)
179 | jekyll (> 3.5, < 5.0)
180 | jekyll-github-metadata (~> 2.9)
181 | jekyll-seo-tag (~> 2.0)
182 | jekyll-theme-slate (0.1.1)
183 | jekyll (~> 3.5)
184 | jekyll-seo-tag (~> 2.0)
185 | jekyll-theme-tactile (0.1.1)
186 | jekyll (~> 3.5)
187 | jekyll-seo-tag (~> 2.0)
188 | jekyll-theme-time-machine (0.1.1)
189 | jekyll (~> 3.5)
190 | jekyll-seo-tag (~> 2.0)
191 | jekyll-titles-from-headings (0.5.3)
192 | jekyll (>= 3.3, < 5.0)
193 | jekyll-watch (2.2.1)
194 | listen (~> 3.0)
195 | jemoji (0.12.0)
196 | gemoji (~> 3.0)
197 | html-pipeline (~> 2.2)
198 | jekyll (>= 3.0, < 5.0)
199 | kramdown (2.3.0)
200 | rexml
201 | kramdown-parser-gfm (1.1.0)
202 | kramdown (~> 2.0)
203 | liquid (4.0.3)
204 | listen (3.4.1)
205 | rb-fsevent (~> 0.10, >= 0.10.3)
206 | rb-inotify (~> 0.9, >= 0.9.10)
207 | mercenary (0.3.6)
208 | minima (2.5.1)
209 | jekyll (>= 3.5, < 5.0)
210 | jekyll-feed (~> 0.9)
211 | jekyll-seo-tag (~> 2.1)
212 | minitest (5.14.4)
213 | multipart-post (2.1.1)
214 | nokogiri (1.11.1-x86_64-darwin)
215 | racc (~> 1.4)
216 | nokogiri (1.11.1-x86_64-linux)
217 | racc (~> 1.4)
218 | octokit (4.20.0)
219 | faraday (>= 0.9)
220 | sawyer (~> 0.8.0, >= 0.5.3)
221 | pathutil (0.16.2)
222 | forwardable-extended (~> 2.6)
223 | public_suffix (4.0.6)
224 | racc (1.5.2)
225 | rb-fsevent (0.10.4)
226 | rb-inotify (0.10.1)
227 | ffi (~> 1.0)
228 | rexml (3.2.4)
229 | rouge (3.26.0)
230 | ruby-enum (0.9.0)
231 | i18n
232 | ruby2_keywords (0.0.4)
233 | rubyzip (2.3.0)
234 | safe_yaml (1.0.5)
235 | sass (3.7.4)
236 | sass-listen (~> 4.0.0)
237 | sass-listen (4.0.0)
238 | rb-fsevent (~> 0.9, >= 0.9.4)
239 | rb-inotify (~> 0.9, >= 0.9.7)
240 | sawyer (0.8.2)
241 | addressable (>= 2.3.5)
242 | faraday (> 0.8, < 2.0)
243 | simpleidn (0.2.1)
244 | unf (~> 0.1.4)
245 | terminal-table (1.8.0)
246 | unicode-display_width (~> 1.1, >= 1.1.1)
247 | thread_safe (0.3.6)
248 | typhoeus (1.4.0)
249 | ethon (>= 0.9.0)
250 | tzinfo (1.2.9)
251 | thread_safe (~> 0.1)
252 | unf (0.1.4)
253 | unf_ext
254 | unf_ext (0.0.7.7)
255 | unicode-display_width (1.7.0)
256 | zeitwerk (2.4.2)
257 |
258 | PLATFORMS
259 | x86_64-darwin-20
260 | x86_64-linux
261 |
262 | DEPENDENCIES
263 | github-pages (~> 212)
264 | minima (~> 2.5)
265 |
266 | BUNDLED WITH
267 | 2.2.14
268 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: minima
2 | title: Rust Verification Tools
3 | author: Google Research
4 | baseurl: "/rust-verification-tools"
5 | gitrepo: https://github.com/project-oak/rust-verification-tools/
6 | show_excerpts: true
7 |
8 | kramdown:
9 | # fix ugly emoji for footnote backlink
10 | # footnote_backlink: '↩' # arrow with round hook (ugly default)
11 | # footnote_backlink: '↢' # arrow
12 | # footnote_backlink: '⬏' # arrow with square hook
13 | footnote_backlink: '⤾' # clockwise semi-circular arrow
14 |
15 | header_pages:
16 | - about.md
17 | - tools.md
18 |
--------------------------------------------------------------------------------
/docs/_internal/howto-blog.md:
--------------------------------------------------------------------------------
1 | # The rust-verificatio-tools blog
2 |
3 | ## Before pushing a new post
4 |
5 | [Install jekyll](https://jekyllrb.com/docs/):
6 |
7 | ``` shell
8 | sudo apt install ruby ruby-dev
9 | gem install jekyll bundler --user-install
10 | export PATH=$HOME/.local/share/gem/ruby/2.7.0/bin:$PATH
11 | bundle config set --local path ~/.local/share/gem/
12 | bundle install
13 | ```
14 |
15 | Check that the blog builds and looks ok:
16 |
17 | ``` shell
18 | # cd docs
19 | bundle exec jekyll serve -o -I -l
20 | ```
21 |
--------------------------------------------------------------------------------
/docs/_posts/2020-09-07-install-crux.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Crux-Mir installation
4 | ---
5 |
6 | The best way to install crux (aka mir-verifier) is to follow the instructions on
7 | [crux's GitHub page][Crux-MIR].
8 |
9 | For convenience, instructions for installing crux and its dependencies are
10 | provided below.
11 |
12 | *[Note: the instructions here are probably out of date. We don't test with crux
13 | often enough to spot when things change.]*
14 |
15 |
16 | We are going to install Haskell, Rust, mir-json, Yices and crux.
17 |
18 | Where possible `apt` is used.
19 | Everything else is installed under `$HOME`.
20 |
21 |
22 | ### Installing Haskell
23 |
24 | ``` shell
25 | sudo apt install cabal-install ghc
26 | cabal new-update
27 | cabal user-config update
28 | ```
29 |
30 | Make sure `PATH` includes `$HOME/.cabal/bin`.
31 |
32 |
33 | ### Installing Rust
34 |
35 | Install rust using rustup.
36 | mir-json requires nightly-2020-03-22 so we will get that.
37 |
38 | ``` shell
39 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
40 | rustup toolchain install nightly-2020-03-22 --force
41 | rustup default nightly-2020-03-22
42 | rustup component add --toolchain nightly-2020-03-22 rustc-dev
43 | ```
44 |
45 | Make sure `PATH` includes `$HOME/.cargo/bin`.
46 |
47 | ### Install mir-json
48 |
49 | ``` shell
50 | git clone git@github.com:GaloisInc/mir-json.git
51 | cd mir-json
52 | RUSTC_WRAPPER=./rustc-rpath.sh cargo install --locked
53 | ```
54 |
55 | ### Install Yices
56 |
57 | ``` shell
58 | git clone git@github.com:SRI-CSL/yices2.git
59 | cd yices2
60 | autoconf
61 | ./configure --prefix="$HOME/.local"
62 | make
63 | make install
64 | ```
65 |
66 | Make sure `PATH` includes `$HOME/.local/bin`
67 |
68 | ### Building Crux
69 |
70 | ``` shell
71 | git clone git@github.com:GaloisInc/mir-verifier.git
72 | cd mir-verifier
73 | git submodule update --init
74 | cabal v2-build
75 | ./translate_libs.sh
76 | cabal v2-install crux-mir
77 | ```
78 |
79 | ### Shell init script
80 |
81 | Add the following lines to your shell init script (assuming crux was cloned into
82 | `$HOME/mir-verifier`).
83 |
84 | ``` shell
85 | export PATH=$HOME/.local/bin:$HOME/.cabal/bin:$HOME/.cargo/bin:$PATH
86 | export CRUX_RUST_LIBRARY_PATH=$HOME/mir-verifier/rlibs
87 | ```
88 | ### Testing
89 |
90 | Run crux's test suite:
91 |
92 | ``` shell
93 | cd mir-verifier
94 | cabal v2-test
95 | # [...]
96 | # All 254 tests passed (322.16s)
97 | # Test suite test: PASS
98 | # Test suite logged to:
99 | # [...]
100 | # 1 of 1 test suites (1 of 1 test cases) passed.
101 | ```
102 |
103 | [CC-rs crate]: https://github.com/alexcrichton/cc-rs/
104 | [Cargo build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
105 | [Clang]: https://clang.llvm.org/
106 | [Crux-MIR]: https://github.com/GaloisInc/mir-verifier/
107 | [Docker]: https://www.docker.com/
108 | [GraalVM and Rust]: https://michaelbh.com/blog/graalvm-and-rust-1/
109 | [Hypothesis]: https://hypothesis.works/
110 | [KLEE]: https://klee.github.io/
111 | [Linux driver verification]: http://linuxtesting.org/ldv/
112 | [LLVM]: https://llvm.org/
113 | [MIR blog post]: https://blog.rust-lang.org/2016/04/19/MIR.html
114 | [PropTest book]: https://altsysrq.github.io/proptest-book/intro.html
115 | [PropTest]: https://github.com/AltSysrq/proptest/
116 | [Rust benchmarks]: https://github.com/soarlab/rust-benchmarks/
117 | [Rust port of QuickCheck]: https://github.com/burntsushi/quickcheck/
118 | [Rust's runtime]: https://blog.mgattozzi.dev/rusts-runtime/
119 | [SMACK]: https://smackers.github.io/
120 | [SV-COMP]: https://sv-comp.sosy-lab.org/2020/rules.php
121 | [std::env::args source code]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/args.rs
122 |
123 | [RVT git repo]: {{site.gitrepo}}/
124 | [cargo-verify source]: {{site.gitrepo}}blob/main/cargo-verify/
125 | [compatibility-test]: {{site.gitrepo}}blob/main/compatibility-test/src
126 | [demos/simple/ffi directory]: {{site.gitrepo}}blob/main/demos/simple/ffi/
127 | [CONTRIBUTING]: {{site.gitrepo}}blob/main/CONTRIBUTING.md
128 | [LICENSE-APACHE]: {{site.gitrepo}}blob/main/LICENSE-APACHE
129 | [LICENSE-MIT]: {{site.gitrepo}}blob/main/LICENSE-MIT
130 |
131 | [Using KLEE]: {{site.baseurl}}{% post_url 2020-09-01-using-klee %}
132 | [Using verification-annotations]: {{site.baseurl}}{% post_url 2020-09-02-using-annotations %}
133 | [Using PropVerify]: {{site.baseurl}}{% post_url 2020-09-03-using-propverify %}
134 | [Install Crux]: {{site.baseurl}}{% post_url 2020-09-07-install-crux %}
135 | [Using ARGV]: {{site.baseurl}}{% post_url 2020-09-09-using-argv %}
136 | [Using FFI]: {{site.baseurl}}{% post_url 2020-12-11-using-ffi %}
137 |
138 |
--------------------------------------------------------------------------------
/docs/_posts/2020-09-09-using-argv.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "Using command-line arguments ('argv')"
4 | permalink: /using-argv/
5 | ---
6 |
7 | {: style="float: left; width: 10%; padding: 1%"}
8 | One important difference between C and Rust is that the C main function expects
9 | to be given a list of command line arguments via `argc`/`argv` function
10 | parameters while Rust programs access their command line arguments via the
11 | `sys::env::args()` library function.
12 |
13 | This raises the problem when verifying Rust programs of how can we pass
14 | command line arguments to a program when we are verifying it.
15 | This document sketches how Rust's command line arguments work (on Linux)
16 | and how we can set them when verifying Rust programs.
17 |
18 | _[Note:
19 | You should not need any of the information in this note to
20 | use `propverify` if you are using the `cargo-verify` script.
21 | These instructions are mostly useful if you want to create your own
22 | tools or if you hit problems.]_
23 |
24 |
25 | ## How Rust handles command-line arguments (on Linux)
26 |
27 | _[For more information about this, see [this blog post][Rust's runtime]
28 | and, of course, [the source code][std-env-args source code].]_
29 |
30 | The Rust runtime system provides an initializer function
31 | `ARGV_INIT_ARRAY::init_wrapper(argc, argv, envp)` that saves the values of
32 | `argc` and `argv` in global variables so that they can be accessed later by
33 | `std::env::args()` and it places a pointer to this function in a global variable
34 | in an ELF section called `.init_array_000099`.
35 |
36 | When the Linux kernel runs a Rust program, it starts by executing code from the GNU C
37 | library. This library calls some initialization functions before calling the
38 | Rust `main` function. These initialization functions are found in ELF
39 | sections with names like `.init_array` and they expect to be called with three
40 | arguments: `argc`, `argv` and `envp`.
41 |
42 |
43 | ## How our tools handle command-line arguments
44 |
45 | To make it possible to pass command-line arguments to a program when it is being
46 | verified, we need to arrange that the initialization functions are called and that
47 | they are passed the values of `argc` and `argv`.
48 | (I am unsure whether we also need to pass the value of `envp`.)
49 |
50 | Since verification tools like `KLEE` are normally used to verify C programs,
51 | they expect to start with a call to `main(argc, argv)` so, to verify Rust programs,
52 | we need to arrange that calling `main` will call any initialization functions.
53 | We do this by transforming the LLVM bitcode file generated by the Rust compiler
54 | so that the first thing that `main` does is to call all the initialization functions
55 | and to pass them the values of `argc/argv`.
56 | The `cargo-verify` script invokes this transformation if any command line arguments
57 | are passed to the program.
58 |
59 | This results in an LLVM `main` function like this (the change is the third line that calls `__init_function`).
60 |
61 | ```
62 | define i32 @main(i32 %0, i8** nocapture readnone %1) unnamed_addr #5 {
63 | top:
64 | call void @__init_function(i32 %0, i8** %1, i8** null)
65 | %2 = load volatile i8, i8* getelementptr inbounds ([34 x i8], [34 x i8]* @__rustc_debug_gdb_scripts_section__, i64 0, i64 0), align 1
66 | %3 = sext i32 %0 to i64
67 | %4 = call i64 @_ZN3std2rt10lang_start17ha6542edf6afbeb15E(void ()* @_ZN4argv4main17h878bf90218e36557E, i64 %3, i8** %1)
68 | %5 = trunc i64 %4 to i32
69 | call void @klee.dtor_stub()
70 | ret i32 %5
71 | }
72 | ```
73 |
74 | and the `__init_function` that calls all the initializers looks like this
75 |
76 | ```
77 | define void @__init_function(i32 %0, i8** %1, i8** %2) {
78 | entry:
79 | call void @_ZN3std3sys4unix4args3imp15ARGV_INIT_ARRAY12init_wrapper17hac2c035213cf4e54E(i32 %0, i8** %1, i8** %2)
80 | ret void
81 | }
82 | ```
83 |
84 | [CC-rs crate]: https://github.com/alexcrichton/cc-rs/
85 | [Cargo build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
86 | [Clang]: https://clang.llvm.org/
87 | [Crux-MIR]: https://github.com/GaloisInc/mir-verifier/
88 | [Docker]: https://www.docker.com/
89 | [GraalVM and Rust]: https://michaelbh.com/blog/graalvm-and-rust-1/
90 | [Hypothesis]: https://hypothesis.works/
91 | [KLEE]: https://klee.github.io/
92 | [Linux driver verification]: http://linuxtesting.org/ldv/
93 | [LLVM]: https://llvm.org/
94 | [MIR blog post]: https://blog.rust-lang.org/2016/04/19/MIR.html
95 | [PropTest book]: https://altsysrq.github.io/proptest-book/intro.html
96 | [PropTest]: https://github.com/AltSysrq/proptest/
97 | [Rust benchmarks]: https://github.com/soarlab/rust-benchmarks/
98 | [Rust port of QuickCheck]: https://github.com/burntsushi/quickcheck/
99 | [Rust's runtime]: https://blog.mgattozzi.dev/rusts-runtime/
100 | [SMACK]: https://smackers.github.io/
101 | [SV-COMP]: https://sv-comp.sosy-lab.org/2020/rules.php
102 | [std-env-args source code]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/args.rs
103 |
104 | [RVT git repo]: {{site.gitrepo}}/
105 | [cargo-verify source]: {{site.gitrepo}}blob/main/cargo-verify/
106 | [compatibility-test]: {{site.gitrepo}}blob/main/compatibility-test/src
107 | [demos/simple/ffi directory]: {{site.gitrepo}}blob/main/demos/simple/ffi/
108 | [CONTRIBUTING]: {{site.gitrepo}}blob/main/CONTRIBUTING.md
109 | [LICENSE-APACHE]: {{site.gitrepo}}blob/main/LICENSE-APACHE
110 | [LICENSE-MIT]: {{site.gitrepo}}blob/main/LICENSE-MIT
111 |
112 | [Using KLEE]: {{site.baseurl}}{% post_url 2020-09-01-using-klee %}
113 | [Using verification-annotations]: {{site.baseurl}}{% post_url 2020-09-02-using-annotations %}
114 | [Using PropVerify]: {{site.baseurl}}{% post_url 2020-09-03-using-propverify %}
115 | [Install Crux]: {{site.baseurl}}{% post_url 2020-09-07-install-crux %}
116 | [Using ARGV]: {{site.baseurl}}{% post_url 2020-09-09-using-argv %}
117 | [Using FFI]: {{site.baseurl}}{% post_url 2020-12-11-using-ffi %}
118 |
119 |
--------------------------------------------------------------------------------
/docs/assets/main.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "{{ site.theme }}";
5 |
6 | body {
7 | background: #fffff8;
8 | }
9 |
10 | pre, code, .highlighter-rouge .highlight {
11 | background: #f8f8f0;
12 | }
13 |
14 | .posts > .post {
15 | padding-bottom: 2em;
16 | }
17 |
18 | .posts > .post:last-child {
19 | padding-bottom: 1em;
20 | }
21 |
22 | .post {
23 | .read-more {
24 | text-transform: uppercase;
25 | font-size: 15px;
26 | }
27 | }
28 |
29 | // Fix appearance of footnotes
30 | sup {
31 | vertical-align: super;
32 | font-size: x-small;
33 | }
34 |
35 |
36 | /*!
37 | * "Fork me on GitHub" CSS ribbon v0.2.3 | MIT License
38 | * https://github.com/simonwhitaker/github-fork-ribbon-css
39 | */
40 |
41 | .github-fork-ribbon {
42 | width: 12.1em;
43 | height: 12.1em;
44 | position: absolute;
45 | overflow: hidden;
46 | top: 0;
47 | right: 0;
48 | z-index: 9999;
49 | pointer-events: none;
50 | font-size: 13px;
51 | text-decoration: none;
52 | text-indent: -999999px;
53 | }
54 |
55 | .github-fork-ribbon.fixed {
56 | position: fixed;
57 | }
58 |
59 | .github-fork-ribbon:hover, .github-fork-ribbon:active {
60 | background-color: rgba(0, 0, 0, 0.0);
61 | }
62 |
63 | .github-fork-ribbon:before, .github-fork-ribbon:after {
64 | /* The right and left classes determine the side we attach our banner to */
65 | position: absolute;
66 | display: block;
67 | width: 15.38em;
68 | height: 1.54em;
69 |
70 | top: 3.23em;
71 | right: -3.23em;
72 |
73 | -webkit-box-sizing: content-box;
74 | -moz-box-sizing: content-box;
75 | box-sizing: content-box;
76 |
77 | -webkit-transform: rotate(45deg);
78 | -moz-transform: rotate(45deg);
79 | -ms-transform: rotate(45deg);
80 | -o-transform: rotate(45deg);
81 | transform: rotate(45deg);
82 | }
83 |
84 | .github-fork-ribbon:before {
85 | content: "";
86 |
87 | /* Add a bit of padding to give some substance outside the "stitching" */
88 | padding: .38em 0;
89 |
90 | /* Set the base colour */
91 | background-color: #a00;
92 |
93 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
94 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15)));
95 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
96 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
97 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
98 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
99 | background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
100 |
101 | /* Add a drop shadow */
102 | -webkit-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
103 | -moz-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
104 | box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
105 |
106 | pointer-events: auto;
107 | }
108 |
109 | .github-fork-ribbon:after {
110 | /* Set the text from the data-ribbon attribute */
111 | content: attr(data-ribbon);
112 |
113 | /* Set the text properties */
114 | color: #fff;
115 | font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif;
116 | line-height: 1.54em;
117 | text-decoration: none;
118 | text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);
119 | text-align: center;
120 | text-indent: 0;
121 |
122 | /* Set the layout properties */
123 | padding: .15em 0;
124 | margin: .15em 0;
125 |
126 | /* Add "stitching" effect */
127 | border-width: .08em 0;
128 | border-style: dotted;
129 | border-color: #fff;
130 | border-color: rgba(255, 255, 255, 0.7);
131 | }
132 |
133 | .github-fork-ribbon.left-top, .github-fork-ribbon.left-bottom {
134 | right: auto;
135 | left: 0;
136 | }
137 |
138 | .github-fork-ribbon.left-bottom, .github-fork-ribbon.right-bottom {
139 | top: auto;
140 | bottom: 0;
141 | }
142 |
143 | .github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after {
144 | right: auto;
145 | left: -3.23em;
146 | }
147 |
148 | .github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
149 | top: auto;
150 | bottom: 3.23em;
151 | }
152 |
153 | .github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
154 | -webkit-transform: rotate(-45deg);
155 | -moz-transform: rotate(-45deg);
156 | -ms-transform: rotate(-45deg);
157 | -o-transform: rotate(-45deg);
158 | transform: rotate(-45deg);
159 | }
160 |
--------------------------------------------------------------------------------
/docs/images/Kangrejos.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/Kangrejos.pdf
--------------------------------------------------------------------------------
/docs/images/profiling-regex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/profiling-regex.png
--------------------------------------------------------------------------------
/docs/images/retrospective-all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/retrospective-all.png
--------------------------------------------------------------------------------
/docs/images/retrospective-horizontal-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/retrospective-horizontal-50.png
--------------------------------------------------------------------------------
/docs/images/retrospective-shift-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/retrospective-shift-left.png
--------------------------------------------------------------------------------
/docs/images/retrospective-vertical-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/retrospective-vertical-10.png
--------------------------------------------------------------------------------
/docs/images/retrospective-vertical-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-oak/rust-verification-tools/b179e90daa9ec77c2a81b903ff832aaca4f87b5b/docs/images/retrospective-vertical-50.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 | regenerate: true
4 | ---
5 |
6 | [RVT][RVT git repo] is a collection of research tools/libraries to support both static verification
7 | (formal verification) and dynamic verification (testing) of Rust.
8 | You can download RVT from
9 | [https://github.com/project-oak/rust-verification-tools/](https://github.com/project-oak/rust-verification-tools/);
10 | RVT is dual-licensed ([Apache][LICENSE-APACHE]/[MIT][LICENSE-MIT]) so that you can use and adapt our
11 | code for your own tools.
12 |
13 | Fork me on GitHub
14 |
15 |
16 | [CC-rs crate]: https://github.com/alexcrichton/cc-rs/
17 | [Cargo build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
18 | [Clang]: https://clang.llvm.org/
19 | [Crux-MIR]: https://github.com/GaloisInc/mir-verifier/
20 | [Docker]: https://www.docker.com/
21 | [GraalVM and Rust]: https://michaelbh.com/blog/graalvm-and-rust-1/
22 | [Hypothesis]: https://hypothesis.works/
23 | [KLEE]: https://klee.github.io/
24 | [Linux driver verification]: http://linuxtesting.org/ldv/
25 | [LLVM]: https://llvm.org/
26 | [MIR blog post]: https://blog.rust-lang.org/2016/04/19/MIR.html
27 | [PropTest book]: https://altsysrq.github.io/proptest-book/intro.html
28 | [PropTest]: https://github.com/AltSysrq/proptest/
29 | [Rust benchmarks]: https://github.com/soarlab/rust-benchmarks/
30 | [Rust port of QuickCheck]: https://github.com/burntsushi/quickcheck/
31 | [Rust's runtime]: https://blog.mgattozzi.dev/rusts-runtime/
32 | [SMACK]: https://smackers.github.io/
33 | [SV-COMP]: https://sv-comp.sosy-lab.org/2020/rules.php
34 | [std::env::args source code]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/args.rs
35 |
36 | [RVT git repo]: {{site.gitrepo}}/
37 | [cargo-verify source]: {{site.gitrepo}}blob/main/cargo-verify/
38 | [compatibility-test]: {{site.gitrepo}}blob/main/compatibility-test/src
39 | [demos/simple/ffi directory]: {{site.gitrepo}}blob/main/demos/simple/ffi/
40 | [CONTRIBUTING]: {{site.gitrepo}}blob/main/CONTRIBUTING.md
41 | [LICENSE-APACHE]: {{site.gitrepo}}blob/main/LICENSE-APACHE
42 | [LICENSE-MIT]: {{site.gitrepo}}blob/main/LICENSE-MIT
43 |
44 | [Using KLEE]: {{site.baseurl}}{% post_url 2020-09-01-using-klee %}
45 | [Using verification-annotations]: {{site.baseurl}}{% post_url 2020-09-02-using-annotations %}
46 | [Using PropVerify]: {{site.baseurl}}{% post_url 2020-09-03-using-propverify %}
47 | [Install Crux]: {{site.baseurl}}{% post_url 2020-09-07-install-crux %}
48 | [Using ARGV]: {{site.baseurl}}{% post_url 2020-09-09-using-argv %}
49 | [Using FFI]: {{site.baseurl}}{% post_url 2020-12-11-using-ffi %}
50 |
51 |
--------------------------------------------------------------------------------
/docs/tools.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Tools and libraries
4 | permalink: /tools/
5 | ---
6 |
7 | ## Tools
8 |
9 | - `cargo-verify`: a tool for compiling a crate and
10 | either verifying main/tests or for fuzzing main/tests.
11 | (Use the `--backend` flag to select which.)
12 |
13 | `cargo-verify` uses similar command-line flags to the standard `cargo-test` tool.
14 | The `--script=PATH` flag generates a list of all the commands executed
15 | by `cargo-verify`.
16 |
17 | The source code is [here][cargo-verify source].
18 |
19 | - `rvt-patch-llvm`: a tool for preprocessing LLVM bitfiles before verification.
20 | (Used by `cargo-verify`.)
21 |
22 | This fixes problems in LLVM bitfiles that are designed to be used for
23 | compilation or execution including
24 |
25 | - `--features` causes all processor feature test functions to return false.
26 | This is useful for disabling hand-vectorized code.
27 |
28 | See [Using FFI] for details.
29 |
30 | - `--initializers` causes `main` to call all initializers before it runs.
31 | This is useful for programs that use `std::env::args()` to access the
32 | command line arguments.
33 |
34 | See [Using ARGV] for details.
35 |
36 | - `--seahorn` fixes various problems that affect the [SeaHorn] backend.
37 |
38 | The source code is [here][rvt-patch-llvm source].
39 |
40 | - `rust2calltree`: a tool for fixing (demangling) function names in
41 | kcachegrind profile files.
42 |
43 | See [Profiling Rust] for usage.
44 |
45 | The source code is [here][rust2calltree source].
46 |
47 |
48 | ## Libraries
49 |
50 | - [`verification-annotations` crate][verification-annotations source]: an FFI layer for creating symbolic values in
51 | [KLEE], [Crux-MIR] or [SeaHorn].
52 |
53 | See [Using verification-annotations] for details.
54 |
55 | - [`propverify` crate][propverify source]:
56 | an implementation of the [proptest](https://github.com/AltSysrq/proptest)
57 | library for use with static verification tools.
58 |
59 | See [Using PropVerify] for usage.
60 |
61 |
62 | - [`compatibility-test` test crate][compatibility-test]:
63 | test programs that can be verified either using the original `proptest`
64 | library or using `propverify`.
65 | Used to check that proptest and propverify are compatible with each other.
66 |
67 | Partly based on examples in the [PropTest book].
68 |
69 |
70 | [CC-rs crate]: https://github.com/alexcrichton/cc-rs/
71 | [Cargo build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
72 | [Clang]: https://clang.llvm.org/
73 | [Crux-MIR]: https://github.com/GaloisInc/mir-verifier/
74 | [Docker]: https://www.docker.com/
75 | [GraalVM and Rust]: https://michaelbh.com/blog/graalvm-and-rust-1/
76 | [Hypothesis]: https://hypothesis.works/
77 | [KLEE]: https://klee.github.io/
78 | [Linux driver verification]: http://linuxtesting.org/ldv/
79 | [LLVM]: https://llvm.org/
80 | [MIR blog post]: https://blog.rust-lang.org/2016/04/19/MIR.html
81 | [PropTest book]: https://altsysrq.github.io/proptest-book/intro.html
82 | [PropTest]: https://github.com/AltSysrq/proptest/
83 | [Rust benchmarks]: https://github.com/soarlab/rust-benchmarks/
84 | [Rust port of QuickCheck]: https://github.com/burntsushi/quickcheck/
85 | [Rust's runtime]: https://blog.mgattozzi.dev/rusts-runtime/
86 | [SeaHorn]: https://seahorn.github.io/
87 | [SMACK]: https://smackers.github.io/
88 | [SV-COMP]: https://sv-comp.sosy-lab.org/2020/rules.php
89 | [std::env::args source code]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/args.rs
90 |
91 | [HATRA 2020]: https://alastairreid.github.io/papers/HATRA_20/
92 |
93 | [RVT git repo]: {{site.gitrepo}}/
94 | [cargo-verify source]: {{site.gitrepo}}blob/main/cargo-verify/
95 | [verification-annotations source]: {{site.gitrepo}}blob/main/verification-annotations/
96 | [rust2calltree source]: {{site.gitrepo}}blob/main/rust2calltree/
97 | [rvt-patch-llvm source]: {{site.gitrepo}}blob/main/rvt-patch-llvm/
98 | [compatibility-test]: {{site.gitrepo}}blob/main/compatibility-test/src
99 | [propverify source]: {{site.gitrepo}}blob/main/propverify/
100 | [demos/simple/ffi directory]: {{site.gitrepo}}blob/main/demos/simple/ffi/
101 | [CONTRIBUTING]: {{site.gitrepo}}blob/main/CONTRIBUTING.md
102 | [LICENSE-APACHE]: {{site.gitrepo}}blob/main/LICENSE-APACHE
103 | [LICENSE-MIT]: {{site.gitrepo}}blob/main/LICENSE-MIT
104 |
105 | [Using KLEE]: {{site.baseurl}}{% post_url 2020-09-01-using-klee %}
106 | [Using verification-annotations]: {{site.baseurl}}{% post_url 2020-09-02-using-annotations %}
107 | [Using PropVerify]: {{site.baseurl}}{% post_url 2020-09-03-using-propverify %}
108 | [Install Crux]: {{site.baseurl}}{% post_url 2020-09-07-install-crux %}
109 | [Using ARGV]: {{site.baseurl}}{% post_url 2020-09-09-using-argv %}
110 | [Using FFI]: {{site.baseurl}}{% post_url 2020-12-11-using-ffi %}
111 | [Profiling Rust]: {{site.baseurl}}{% post_url 2021-03-12-profiling-rust %}
112 |
113 |
--------------------------------------------------------------------------------
/docs/using-klee.md:
--------------------------------------------------------------------------------
1 | This page has moved to https://project-oak.github.io/rust-verification-tools/using-klee/
2 |
--------------------------------------------------------------------------------
/propverify/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of Propverify's significant contributors.
2 | #
3 | # This does not necessarily list everyone who has contributed code,
4 | # especially since many employees of one corporation may be contributing.
5 | # To see the full list of contributors, see the revision history in
6 | # source control.
7 | Google LLC
8 |
--------------------------------------------------------------------------------
/propverify/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic
7 | Versioning](https://semver.org/spec/v2.0.0.html).
8 |
9 | ## [Unreleased]
10 |
11 | ### Added
12 |
13 |
14 | ### Changed
15 |
16 | [0.0.2]: https://github.com/project-oak/rust-verification-tools/compare/v0.0.1...v0.0.2
17 | [0.0.1]: https://github.com/project-oak/rust-verification-tools/releases/tag/v0.0.1
18 |
--------------------------------------------------------------------------------
/propverify/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement (CLA). You (or your employer) retain the copyright to your
10 | contribution; this simply gives us permission to use and redistribute your
11 | contributions as part of the project. Head over to
12 | to see your current agreements on file or
13 | to sign a new one.
14 |
15 | You generally only need to submit a CLA once, so if you've already submitted one
16 | (even if it was for a different project), you probably don't need to do it
17 | again.
18 |
19 | ## Code reviews
20 |
21 | All submissions, including submissions by project members, require review. We
22 | use GitHub pull requests for this purpose. Consult
23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
24 | information on using pull requests.
25 |
26 | ## Community Guidelines
27 |
28 | This project follows
29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
30 |
--------------------------------------------------------------------------------
/propverify/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "propverify"
3 | version = "0.1.0"
4 | authors = [
5 | "Alastair Reid ",
6 | "Shaked Flur "
7 | ]
8 | edition = "2018"
9 | description = "Library for building verification test harnesses that implements the proptest API"
10 | categories = ["development-tools::testing"]
11 | keywords = ["klee", "proptest", "property", "verification", "testing", "quickcheck", "fuzz", "hypothesis"]
12 | license = "MIT OR Apache-2.0"
13 | readme = "README.md"
14 |
15 | [features]
16 | # Enable support for symbolic f32 and f64
17 | float = []
18 |
19 | verifier-klee = [ "verification-annotations/verifier-klee", "float" ]
20 | verifier-crux = [ "verification-annotations/verifier-crux" ]
21 | verifier-seahorn = [ "verification-annotations/verifier-seahorn" ]
22 | verifier-smack = [ "verification-annotations/verifier-smack" ]
23 |
24 | [dependencies]
25 | verification-annotations = { path = "../verification-annotations" }
26 |
--------------------------------------------------------------------------------
/propverify/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2020 The Propverify Authors.
2 | Based on parts of proptest which is Copyright 2017, 2018 Jason Lingle.
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/propverify/README.md:
--------------------------------------------------------------------------------
1 | # `propverify`
2 |
3 | This is a library/DSL for writing verification harnesses.
4 |
5 | We see formal verification and testing as two parts of the same
6 | activity and so this library is designed to be compatible
7 | with the
8 | [proptest](https://github.com/AltSysrq/proptest)
9 | fuzzing/property testing library
10 | so that you can use the same harness with
11 | either a formal verification tool or with a fuzzing tool.
12 |
13 | ## License
14 |
15 | Licensed under either of
16 |
17 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
18 | http://www.apache.org/licenses/LICENSE-2.0)
19 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or
20 | http://opensource.org/licenses/MIT)
21 |
22 | at your option.
23 |
24 | ## Acknowledgements
25 |
26 | This crate is heavily based on the design and API of the wonderful
27 | [proptest](https://github.com/AltSysrq/proptest)
28 | fuzz-testing library.
29 | The implementation also borrows techniques, tricks and code
30 | from the implementation - you can learn a lot about how to write
31 | an embedded DSL from reading the proptest code.
32 |
33 | In turn, proptest was influenced by
34 | the [Rust port of QuickCheck](https://github.com/burntsushi/quickcheck)
35 | and
36 | the [Hypothesis](https://hypothesis.works/) fuzzing/property testing library Python.
37 | (proptest also acknowledges `regex_generate` – but we have not yet implemented
38 | regex strategies for this library.)
39 |
40 | ### Contribution
41 |
42 | Unless you explicitly state otherwise, any contribution intentionally
43 | submitted for inclusion in the
44 | work by you, as defined in the Apache-2.0 license, shall be dual licensed as
45 | above, without any
46 | additional terms or conditions.
47 |
--------------------------------------------------------------------------------
/propverify/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | // Based on parts of Proptest which is Copyright 2017, 2018 Jason Lingle
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | mod strategy;
11 |
12 | pub mod prelude {
13 | // Macros
14 | pub use crate::prop_assume;
15 | pub use crate::prop_compose;
16 | pub use crate::prop_oneof;
17 | pub use crate::proptest;
18 |
19 | // Functions and types
20 | pub use crate::strategy::of;
21 | pub use crate::strategy::prop_is_replay;
22 | pub use crate::strategy::Just;
23 | pub use crate::strategy::Strategy;
24 | pub use crate::strategy::{maybe_err, maybe_ok};
25 |
26 | // Modules with same name as types
27 | pub use crate::strategy::{bool, char};
28 |
29 | // Arbitrary trait
30 | pub use crate::strategy::{any, Arbitrary};
31 |
32 | pub mod prop {
33 | pub use crate::strategy::prop_is_replay;
34 | pub use crate::strategy::{uniform0, uniform1, uniform2, uniform3, uniform4};
35 | pub use crate::strategy::{uniform10, uniform11, uniform12, uniform13, uniform14};
36 | pub use crate::strategy::{uniform15, uniform16, uniform17, uniform18, uniform19};
37 | pub use crate::strategy::{uniform20, uniform21, uniform22, uniform23, uniform24};
38 | pub use crate::strategy::{uniform25, uniform26, uniform27, uniform28, uniform29};
39 | pub use crate::strategy::{uniform30, uniform31, uniform32};
40 | pub use crate::strategy::{uniform5, uniform6, uniform7, uniform8, uniform9};
41 | pub mod collection {
42 | pub use crate::strategy::binary_heap;
43 | pub use crate::strategy::btree_map;
44 | pub use crate::strategy::btree_set;
45 | pub use crate::strategy::linked_list;
46 | pub use crate::strategy::vec;
47 | pub use crate::strategy::vec_deque;
48 | }
49 | pub mod num {
50 | #[cfg(feature = "float")]
51 | pub use crate::strategy::{f32, f64};
52 | pub use crate::strategy::{i128, i16, i32, i64, i8, isize};
53 | pub use crate::strategy::{u128, u16, u32, u64, u8, usize};
54 | }
55 |
56 | pub use crate::strategy::string;
57 | }
58 |
59 | pub use verification_annotations;
60 | pub use verification_annotations::verifier;
61 |
62 | pub use verifier::assert as prop_assert;
63 | pub use verifier::assert_eq as prop_assert_eq;
64 | pub use verifier::assert_ne as prop_assert_ne;
65 | }
66 |
--------------------------------------------------------------------------------
/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | build_*
2 | rvt-*.bc
3 |
--------------------------------------------------------------------------------
/runtime/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of Rust verification tool's significant contributors.
2 | #
3 | # This does not necessarily list everyone who has contributed code,
4 | # especially since many employees of one corporation may be contributing.
5 | # To see the full list of contributors, see the revision history in
6 | # source control.
7 | Google LLC
8 |
--------------------------------------------------------------------------------
/runtime/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement (CLA). You (or your employer) retain the copyright to your
10 | contribution; this simply gives us permission to use and redistribute your
11 | contributions as part of the project. Head over to
12 | to see your current agreements on file or
13 | to sign a new one.
14 |
15 | You generally only need to submit a CLA once, so if you've already submitted one
16 | (even if it was for a different project), you probably don't need to do it
17 | again.
18 |
19 | ## Code reviews
20 |
21 | All submissions, including submissions by project members, require review. We
22 | use GitHub pull requests for this purpose. Consult
23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
24 | information on using pull requests.
25 |
26 | ## Community Guidelines
27 |
28 | This project follows
29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
30 |
--------------------------------------------------------------------------------
/runtime/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2020 The Rust verification tools Authors.
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/runtime/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Rust verification tools Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 or the MIT license
5 | # , at your
6 | # option. This file may not be copied, modified, or distributed
7 | # except according to those terms.
8 |
9 | # default target backend: override on command line
10 | TGT = klee
11 |
12 | # this rule comes first to make sure that it is the default target
13 | default: rvt-$(TGT).bc
14 |
15 | CC = clang-${LLVM_VERSION}
16 | CFLAGS = -flto=thin
17 | CFLAGS += -O1
18 |
19 | LINK = llvm-link-${LLVM_VERSION}
20 |
21 | C_SRCS := $(wildcard src/*.c)
22 | OBJS := $(patsubst src/%.c, build_$(TGT)/%.o, $(C_SRCS))
23 |
24 | build_$(TGT)/%.o: src/%.c
25 | mkdir -p build_$(TGT)
26 | $(CC) $(CFLAGS) $^ -c -o $@
27 |
28 | rvt-$(TGT).bc: $(OBJS)
29 | $(LINK) $(OBJS) -o $@
30 |
31 | clean::
32 | $(RM) $(OBJS)
33 | $(RM) rvt-$(TGT).bc
34 |
35 | # End of Makefile
36 |
--------------------------------------------------------------------------------
/runtime/README.md:
--------------------------------------------------------------------------------
1 | # `Rust verification runtime`
2 |
3 | The primary purpose of this library is to provide implementations of
4 | C libraries that the Rust standard library and/or popular crates
5 | depends on.
6 |
7 | The implementations will often make use of the runtimes provided
8 | by each verification backend so the library will be compiled
9 | separately for each verification backend.
10 |
11 |
12 | ## License
13 |
14 | Licensed under either of
15 |
16 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
17 | http://www.apache.org/licenses/LICENSE-2.0)
18 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or
19 | http://opensource.org/licenses/MIT)
20 |
21 | at your option.
22 |
23 | ### Contribution
24 |
25 | Unless you explicitly state otherwise, any contribution intentionally
26 | submitted for inclusion in the
27 | work by you, as defined in the Apache-2.0 license, shall be dual licensed as
28 | above, without any
29 | additional terms or conditions.
30 |
--------------------------------------------------------------------------------
/runtime/src/atexit.c:
--------------------------------------------------------------------------------
1 | int __cxa_atexit(void (*fn)(void*),
2 | void *arg,
3 | void *dso_handle) {
4 | return 0;
5 | }
6 |
7 | // This variant is part of more recent glibc versions and
8 | // is required by the Rust standard library
9 | int __cxa_thread_atexit_impl(void (*fn)(void*), void *arg, void *dso_handle) {
10 | return __cxa_atexit(fn, arg, dso_handle);
11 | }
12 |
--------------------------------------------------------------------------------
/runtime/src/memrchr.c:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Rust verification tools Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #include
10 |
11 | void *memrchr(const void *s, int c, size_t n) {
12 | void *r = NULL;
13 | for(size_t i = 0; i < n && *(char*)s != '\0'; ++i, ++s) {
14 | if (*(char*)s == c) {
15 | r = (void*)s;
16 | }
17 | }
18 | return r;
19 | }
20 |
--------------------------------------------------------------------------------
/runtime/src/posix_memalign.c:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Rust verification tools Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | int posix_memalign(void **memptr, size_t alignment, size_t size) {
14 | if (size == 0) { // allocate a unique address for size 0
15 | size = 1;
16 | }
17 |
18 | void *addr = memalign(alignment, size);
19 | if (!addr) {
20 | // *memptr is not modified on failure
21 | return ENOMEM;
22 | }
23 |
24 | *memptr = addr;
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/runtime/src/pthread.c:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Rust verification tools Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | // Very basic pthread support
10 | //
11 | // - only supports one thread!
12 | // - all functions do nothing and report success
13 | // - functions that return values return 0 or NULL
14 |
15 | #include "pthread.h"
16 |
17 | /***/
18 |
19 | int pthread_attr_init (pthread_attr_t *__attr) {
20 | return 0;
21 | }
22 |
23 | int pthread_attr_getstack (const pthread_attr_t * __attr,
24 | void ** __stackaddr,
25 | size_t * __stacksize) {
26 | *__stackaddr = 0;
27 | *__stacksize = 0;
28 | return 0;
29 | }
30 |
31 | int pthread_attr_destroy (pthread_attr_t *__attr) {
32 | return 0;
33 | }
34 |
35 | int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) {
36 | return 0;
37 | }
38 |
39 | /***/
40 |
41 | int pthread_cond_init (pthread_cond_t * __cond, const pthread_condattr_t * __cond_attr) {
42 | return 0;
43 | }
44 |
45 | int pthread_cond_destroy (pthread_cond_t *__cond) {
46 | return 0;
47 | }
48 |
49 | int pthread_cond_signal (pthread_cond_t *__cond) {
50 | return 0;
51 | }
52 |
53 | int pthread_cond_wait (pthread_cond_t * __cond, pthread_mutex_t * __mutex) {
54 | return 0;
55 | }
56 |
57 | /***/
58 |
59 | int pthread_condattr_init (pthread_condattr_t *__attr) {
60 | return 0;
61 | }
62 |
63 | int pthread_condattr_destroy (pthread_condattr_t *__attr) {
64 | return 0;
65 | }
66 |
67 | int pthread_condattr_setclock (pthread_condattr_t *__attr, __clockid_t __clock_id) {
68 | return 0;
69 | }
70 |
71 | /***/
72 |
73 | static void *specific_value[1000];
74 |
75 | void *pthread_getspecific (pthread_key_t __key) {
76 | return specific_value[__key];
77 | }
78 |
79 | int pthread_setspecific (pthread_key_t __key, const void *__pointer) {
80 | specific_value[__key] = (void*)__pointer;
81 | return 0;
82 | }
83 |
84 | int pthread_key_create (pthread_key_t *__key, void (*__destr_function) (void *)) {
85 | /* Some programs expect value that is not 0, so we'll start from 1 */
86 | static pthread_key_t next = 1;
87 | *__key = next++;
88 | return 0;
89 | }
90 |
91 | int pthread_key_delete (pthread_key_t __key) {
92 | return 0;
93 | }
94 |
95 | /***/
96 |
97 | int pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) {
98 | return 0;
99 | }
100 |
101 | int pthread_mutex_destroy (pthread_mutex_t *__mutex) {
102 | return 0;
103 | }
104 |
105 | int pthread_mutex_lock (pthread_mutex_t *__mutex) {
106 | return 0;
107 | }
108 |
109 | int pthread_mutex_unlock (pthread_mutex_t *__mutex) {
110 | return 0;
111 | }
112 |
113 | /***/
114 |
115 | int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) {
116 | return 0;
117 | }
118 | int pthread_mutexattr_init (pthread_mutexattr_t *__attr) {
119 | return 0;
120 | }
121 | int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) {
122 | return 0;
123 | }
124 |
125 | /***/
126 |
127 | int pthread_rwlock_init (pthread_rwlock_t * __rwlock, const pthread_rwlockattr_t * __attr) {
128 | return 0;
129 | }
130 |
131 | int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) {
132 | return 0;
133 | }
134 |
135 | int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) {
136 | return 0;
137 | }
138 |
139 | int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) {
140 | return 0;
141 | }
142 |
143 | int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) {
144 | return 0;
145 | }
146 |
147 | /***/
148 |
149 | pthread_t pthread_self (void) {
150 | return (pthread_t)0;
151 | }
152 |
153 | // End
154 |
--------------------------------------------------------------------------------
/rust2calltree/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rust2calltree"
3 | version = "0.1.0"
4 | authors = [
5 | "Alastair Reid "
6 | ]
7 | edition = "2018"
8 |
9 | license = "MIT OR Apache-2.0"
10 |
11 | description = "Convert Rust-derived profiles to kcachegrind's calltree input format by demangling function names"
12 |
13 | repository = "https://github.com/project-oak/rust-verification-tools/"
14 | keywords = ["profiling, kcachegrind"]
15 | categories = ["command-line-utilities", "development-tools"]
16 |
17 | [dependencies]
18 | anyhow = "1.0"
19 | log = "0.4"
20 | rustc-demangle = "0.1"
21 | stderrlog = "0.5"
22 | structopt = "0.3"
23 |
24 | [[bin]]
25 | name = "rust2calltree"
26 |
27 |
--------------------------------------------------------------------------------
/rust2calltree/src/main.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use anyhow::{Context, Result};
10 | use log::info;
11 | use rustc_demangle::demangle;
12 | use std::fs::File;
13 | use std::io::{prelude::*, BufReader, BufWriter};
14 | use std::path::PathBuf;
15 | use structopt::StructOpt;
16 |
17 | // Command line argument parsing
18 | #[derive(StructOpt)]
19 | #[structopt(
20 | name = "rust2calltree",
21 | about = "Convert Rust-derived profiles to kcachegrind's calltree input format by demangling function names"
22 | )]
23 | struct Opt {
24 | /// Input file.
25 | #[structopt(name = "INPUT", parse(from_os_str))]
26 | input: PathBuf,
27 |
28 | /// Output file
29 | #[structopt(
30 | short,
31 | long,
32 | name = "OUTPUT",
33 | parse(from_os_str),
34 | default_value = "callgrind.out"
35 | )]
36 | output: PathBuf,
37 |
38 | /// Increase message verbosity
39 | #[structopt(short, long, parse(from_occurrences))]
40 | verbosity: usize,
41 | }
42 |
43 | fn main() -> Result<()> {
44 | let opt = Opt::from_args();
45 |
46 | #[rustfmt::skip]
47 | stderrlog::new()
48 | .verbosity(opt.verbosity)
49 | .init()
50 | .unwrap();
51 |
52 | // Open the input file
53 | let input = opt.input.to_str().unwrap();
54 | info!("Reading input from {}", input);
55 | let input = File::open(input).with_context(|| format!("can't open input file '{}'", input))?;
56 | let input = BufReader::new(input);
57 |
58 | // Open the output file
59 | let output = opt.output.to_str().unwrap();
60 | info!("Writing demangled output to {}", output);
61 | let output =
62 | File::create(&output).with_context(|| format!("can't open output file '{}'", output))?;
63 | let mut output = BufWriter::new(&output);
64 |
65 | for line in input.lines() {
66 | let mut line = line?;
67 | if let Some(s) = line.strip_prefix("fn=") {
68 | line = format!("fn={:#}", demangle(s));
69 | } else if let Some(s) = line.strip_prefix("cfn=") {
70 | line = format!("cfn={:#}", demangle(s));
71 | }
72 | writeln!(output, "{}", line)?;
73 | }
74 |
75 | Ok(())
76 | }
77 |
--------------------------------------------------------------------------------
/rvt-patch-llvm/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rvt-patch-llvm"
3 | version = "0.1.0"
4 | authors = ["Shaked Flur "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | log = "0.4"
11 | stderrlog = "0.5"
12 | structopt = "0.3"
13 | regex = "0.2"
14 |
15 | inkwell = { git = "https://github.com/alastairreid/inkwell" }
16 |
17 | [features]
18 | llvm10 = ["inkwell/llvm10-0"]
19 | llvm11 = ["inkwell/llvm11-0"]
20 |
--------------------------------------------------------------------------------
/scripts/cargo-verify-seahorn.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The Rust verification tool Authors
4 | #
5 | # Licensed under the Apache License, Version 2.0 or the MIT license
7 | # , at your
8 | # option. This file may not be copied, modified, or distributed
9 | # except according to those terms.
10 |
11 | # This is a temporary script for running Seahorn. We should merge this with
12 | # `cargo-verify`. Most of the script is boilerplate for processing command-line
13 | # arguments (see usage below). For the interesting part jump to the 'main'
14 | # function.
15 |
16 | # Debug
17 | # set -x
18 | set -e
19 |
20 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
21 |
22 | usage()
23 | {
24 | cat <&2
52 | exit 2
53 | fi
54 | # Note the quotes around "$args": they are essential!
55 | eval set -- "$args"
56 | unset args
57 |
58 |
59 | while [ $# -gt 0 ] ; do
60 | case "$1" in
61 | '-h'|'--help')
62 | shift
63 | usage
64 | exit 0
65 | ;;
66 | '-c'|'--crate')
67 | readonly CRATE="$2"
68 | shift 2
69 | ;;
70 | '-t'|'--test')
71 | readonly TEST="$2"
72 | shift 2
73 | ;;
74 | '-f'|'--features')
75 | readonly FEATURES="$2"
76 | shift 2
77 | ;;
78 | '-n'|'--no-lto')
79 | shift
80 | LTO=false
81 | ;;
82 | '-i'|'--input')
83 | INPUT="$2"
84 | shift 2
85 | ;;
86 | '-m'|'--mode')
87 | MODE="$2"
88 | shift 2
89 | ;;
90 | '--')
91 | shift
92 | break
93 | ;;
94 | *)
95 | echo "${CMDNAME}: internal error!" >&2
96 | exit 1
97 | ;;
98 | esac
99 | done
100 |
101 | SEAFLAGS=("$@")
102 |
103 | # Default values:
104 | : "${LTO:=true}"
105 | : "${MODE:=ybpf}"
106 |
107 | : "${VCC:="${SCRIPTDIR}/../../verify-c-common"}"
108 | : "${TEMPDIR:=sea-temp}"
109 | }
110 |
111 |
112 | # Extract the file name from $1, without leading path and suffix (if any).
113 | # E.g. 'bname path/to/foo.bar' will echo 'foo'.
114 | bname()
115 | {
116 | # remove prefix
117 | res="${1##*/}"
118 | # remove suffix
119 | res="${res%.*}"
120 | echo "$res"
121 | }
122 |
123 | # Expects rvt-patch-llvm to be installed (i.e. 'cargo install --path .')
124 | RVTPATCHLLVM=rvt-patch-llvm
125 | # As the above takes 5 minutes to build, use the existing debug build instead
126 | # RVTPATCHLLVM="${SCRIPTDIR}/../rvt-patch-llvm/target/debug/rvt-patch-llvm"
127 |
128 | pp_rvt-patch-llvm()
129 | {
130 | if [[ ! "${INPUT}" =~ \.rvt\.(.*\.)*ll$ ]]; then
131 | output="${TEMPDIR}/$(bname "${INPUT}").rvt.ll"
132 | { ENTRY="$("${RVTPATCHLLVM}" -vv -s ${TEST:+-t "${TEST}"} -o "${output}" "${INPUT}" | tee /dev/fd/3 | sed -n 's/^ENTRY: //p')"; } 3>&1
133 | SEAFLAGS=(--entry="${ENTRY}" "${SEAFLAGS[@]}")
134 | INPUT="${output}"
135 | fi
136 | }
137 |
138 | CARGO=(cargo)
139 | # CARGO=(cargo +stage2-for-seahorn -v)
140 |
141 | main()
142 | {
143 | # Use 'cargo' to generate bitcode
144 | if [[ -n "$CRATE" ]]; then
145 | # You might need to do `cargo clean`
146 | rm -f "target/debug/deps/${CRATE}-"*
147 |
148 | # Generate bitcode
149 | RUSTFLAGS="-Cembed-bitcode=yes --emit=llvm-bc ${RUSTFLAGS}"
150 | # Check overflow
151 | RUSTFLAGS="-Warithmetic-overflow -Coverflow-checks=yes ${RUSTFLAGS}"
152 | # Abort, instead of unwind
153 | RUSTFLAGS="-Zpanic_abort_tests -Cpanic=abort ${RUSTFLAGS}"
154 | if [[ "${LTO}" == "true" ]] ; then
155 | # Enable link time optimizations (for us it means generate a big .bc
156 | # file with all the code).
157 | RUSTFLAGS="-Clto ${RUSTFLAGS}"
158 | fi
159 |
160 | export RUSTFLAGS
161 | if [[ -n "${TEST}" ]]; then
162 | "${CARGO[@]}" test --no-run ${FEATURES:+--features "$FEATURES"}
163 | else
164 | "${CARGO[@]}" build ${FEATURES:+--features "$FEATURES"}
165 | fi
166 |
167 | # Find the bitcode that was just generated
168 | INPUT="$(ls -1t "target/debug/deps/${CRATE}-"*.bc | head -1)"
169 | fi
170 |
171 | mkdir -p "$TEMPDIR"
172 |
173 | pp_rvt-patch-llvm
174 |
175 | # Run SeaHorn
176 | case "${MODE}" in
177 | 'ybpf')
178 | sea yama -y "$VCC/seahorn/sea_base.yaml" bpf "${INPUT}" --temp-dir "${TEMPDIR}" "${SEAFLAGS[@]}"
179 | ;;
180 | *)
181 | sea "${MODE}" "${INPUT}" --temp-dir "${TEMPDIR}" "${SEAFLAGS[@]}"
182 | ;;
183 | esac
184 | }
185 |
186 | parse_cmd "$@"
187 | main
188 |
--------------------------------------------------------------------------------
/scripts/regression-test:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 |
3 | set -e
4 | set -x
5 |
6 | (cd demos/simple/annotations; ./verify.sh)
7 | (cd demos/simple/klee; ./verify.sh)
8 | (cd demos/simple/seahorn; ./verify.sh)
9 | (cd demos/simple/errors; ./verify.sh)
10 |
11 | readonly FLAGS="--backend=klee --verbose --clean"
12 | cargo-verify ${FLAGS} --tests --manifest-path=verification-annotations/Cargo.toml
13 | cargo-verify ${FLAGS} --tests --manifest-path=compatibility-test/Cargo.toml
14 | cargo-verify ${FLAGS} --tests --manifest-path=demos/bottlenecks/bornholt2018-1/Cargo.toml
15 | cargo-verify ${FLAGS} --tests --manifest-path=demos/simple/ffi/Cargo.toml
16 | cargo-verify ${FLAGS} -v -v -v --manifest-path=demos/simple/argv/Cargo.toml -- foo foo
17 | cargo verify ${FLAGS} --tests --manifest-path=demos/bottlenecks/merging/Cargo.toml --backend-flags=--use-merge
18 | cargo verify ${FLAGS} --tests --manifest-path=demos/bottlenecks/regex/Cargo.toml
19 | cargo-verify ${FLAGS} --tests --manifest-path=demos/simple/string/Cargo.toml
20 |
21 | # Test the --backend-flags and --replace-backend-flags options.
22 | # Note the use of handlebars and passing args to main (foo foo).
23 | cargo-verify ${FLAGS} --backend-flags='--exit-on-error,--entry-point,{entry},--libc=klee,--silent-klee-assume,--disable-verify,--output-dir,{output_dir},{file},foo,foo' --replace-backend-flags -v -v -v --script run.sh --manifest-path=demos/simple/argv/Cargo.toml
24 |
25 | echo Regression test successful
26 |
--------------------------------------------------------------------------------
/simd_emulation/.gitignore:
--------------------------------------------------------------------------------
1 | *.bc
2 | *.ll
3 | build/
4 |
--------------------------------------------------------------------------------
/simd_emulation/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of Rust verification tool's significant contributors.
2 | #
3 | # This does not necessarily list everyone who has contributed code,
4 | # especially since many employees of one corporation may be contributing.
5 | # To see the full list of contributors, see the revision history in
6 | # source control.
7 | Google LLC
8 |
--------------------------------------------------------------------------------
/simd_emulation/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement (CLA). You (or your employer) retain the copyright to your
10 | contribution; this simply gives us permission to use and redistribute your
11 | contributions as part of the project. Head over to
12 | to see your current agreements on file or
13 | to sign a new one.
14 |
15 | You generally only need to submit a CLA once, so if you've already submitted one
16 | (even if it was for a different project), you probably don't need to do it
17 | again.
18 |
19 | ## Code reviews
20 |
21 | All submissions, including submissions by project members, require review. We
22 | use GitHub pull requests for this purpose. Consult
23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
24 | information on using pull requests.
25 |
26 | ## Community Guidelines
27 |
28 | This project follows
29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
30 |
--------------------------------------------------------------------------------
/simd_emulation/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "simd_emulation"
3 | version = "0.1.0"
4 | authors = ["Alastair Reid "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 |
--------------------------------------------------------------------------------
/simd_emulation/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2021 The Rust verification tools Authors.
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/simd_emulation/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Rust verification tools Authors.
2 | #
3 | # Licensed under the Apache License, Version 2.0 or the MIT license
5 | # , at your
6 | # option. This file may not be copied, modified, or distributed
7 | # except according to those terms.
8 |
9 | # this rule comes first to make sure that it is the default target
10 | default: simd_emulation.bc
11 |
12 | RUSTC ?= rustc
13 | RSFLAGS = --emit=llvm-bc --crate-type=lib -O -Ctarget-feature=+sse2
14 | RSFLAGS += --edition=2018
15 |
16 | LINK = llvm-link-${LLVM_VERSION}
17 |
18 | RS_SRCS := $(wildcard src/*.rs)
19 | RS_OBJS := $(patsubst src/%.rs, build/%.bc, $(RS_SRCS))
20 |
21 | OBJS := $(RS_OBJS)
22 |
23 | build/%.bc: src/%.rs
24 | mkdir -p $(dir $@)
25 | $(RUSTC) $(RSFLAGS) $^ -o $@
26 |
27 | simd_emulation.bc: $(OBJS)
28 | $(LINK) $(OBJS) -o $@
29 |
30 | clean::
31 | $(RM) -r build
32 | $(RM) simd_emulation.bc
33 |
34 | # End of Makefile
35 |
--------------------------------------------------------------------------------
/verification-annotations/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of Propverify's significant contributors.
2 | #
3 | # This does not necessarily list everyone who has contributed code,
4 | # especially since many employees of one corporation may be contributing.
5 | # To see the full list of contributors, see the revision history in
6 | # source control.
7 | Google LLC
8 |
--------------------------------------------------------------------------------
/verification-annotations/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic
7 | Versioning](https://semver.org/spec/v2.0.0.html).
8 |
9 | ## [Unreleased]
10 |
11 | ### Added
12 |
13 | - Change assert! to better match standard Rust
14 | - Added traits NonDet (SMACK) and Symbolic (Crux) to improve compatibility with
15 | other verifiers.
16 | - Added Crux-MIR support.
17 |
18 | ### Changed
19 |
20 | ### Deprecated
21 |
22 | ### Removed
23 |
24 | ### Fixed
25 |
26 | [0.0.2]: https://github.com/project-oak/rust-verification-tools/compare/v0.0.1...v0.0.2
27 | [0.0.1]: https://github.com/project-oak/rust-verification-tools/releases/tag/v0.0.1
28 |
--------------------------------------------------------------------------------
/verification-annotations/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement (CLA). You (or your employer) retain the copyright to your
10 | contribution; this simply gives us permission to use and redistribute your
11 | contributions as part of the project. Head over to
12 | to see your current agreements on file or
13 | to sign a new one.
14 |
15 | You generally only need to submit a CLA once, so if you've already submitted one
16 | (even if it was for a different project), you probably don't need to do it
17 | again.
18 |
19 | ## Code reviews
20 |
21 | All submissions, including submissions by project members, require review. We
22 | use GitHub pull requests for this purpose. Consult
23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
24 | information on using pull requests.
25 |
26 | ## Community Guidelines
27 |
28 | This project follows
29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
30 |
--------------------------------------------------------------------------------
/verification-annotations/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "verification-annotations"
3 | version = "0.1.0"
4 | authors = [
5 | "Alastair Reid ",
6 | "Shaked Flur "
7 | ]
8 | edition = "2018"
9 | description = "verification annotation library"
10 | categories = ["development-tools::testing"]
11 | keywords = ["klee", "crux", "seahorn", "mir", "verification", "testing"]
12 | license = "MIT OR Apache-2.0"
13 |
14 | [features]
15 | default = [ "std" ]
16 | std = []
17 | verifier-crux = []
18 | verifier-klee = []
19 | verifier-seahorn = [ "cc" ]
20 | verifier-smack = [ "cc" ]
21 |
22 | [build-dependencies]
23 | cc = { optional = true, version = "1.0" }
24 |
--------------------------------------------------------------------------------
/verification-annotations/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2020 The Propverify Authors.
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/verification-annotations/README.md:
--------------------------------------------------------------------------------
1 | # `klee-annotations`
2 |
3 | FFI layer for invoking [KLEE](http://klee.github.io/) client API from Rust programs.
4 |
5 | ## License
6 |
7 | Licensed under either of
8 |
9 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
10 | http://www.apache.org/licenses/LICENSE-2.0)
11 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or
12 | http://opensource.org/licenses/MIT)
13 |
14 | at your option.
15 |
16 | ### Contribution
17 |
18 | Unless you explicitly state otherwise, any contribution intentionally
19 | submitted for inclusion in the
20 | work by you, as defined in the Apache-2.0 license, shall be dual licensed as
21 | above, without any
22 | additional terms or conditions.
23 |
--------------------------------------------------------------------------------
/verification-annotations/build.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | fn main() {
10 | println!("cargo:rerun-if-changed=build.rs");
11 | #[cfg(feature = "verifier-seahorn")]
12 | seahorn();
13 | #[cfg(feature = "verifier-smack")]
14 | smack();
15 | }
16 |
17 | #[cfg(feature = "verifier-seahorn")]
18 | fn seahorn() {
19 | println!("cargo:rerun-if-changed=lib/seahorn.c");
20 | cc::Build::new().file("lib/seahorn.c").compile("seahorn");
21 | }
22 |
23 | #[cfg(feature = "verifier-smack")]
24 | fn smack() {
25 | println!("cargo:rerun-if-changed=lib/smack-rust.c");
26 | cc::Build::new()
27 | .file("lib/smack-rust.c")
28 | .define("CARGO_BUILD", None)
29 | .compile("smack");
30 | }
31 |
--------------------------------------------------------------------------------
/verification-annotations/lib/seahorn.c:
--------------------------------------------------------------------------------
1 | // Copyright 2020-2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | void __VERIFIER_error() {
14 | fprintf(stderr, "ERROR: a verification assertion failed.");
15 | exit(1);
16 | }
17 |
18 | void __VERIFIER_assume(int pred) {
19 | if (pred == 0) {
20 | fprintf(stderr, "ERROR: a verification assumption has been violated.");
21 | exit(1);
22 | }
23 | }
24 |
25 | uint8_t __VERIFIER_nondet_u8() { return 0; }
26 | uint16_t __VERIFIER_nondet_u16() { return 0; }
27 | uint32_t __VERIFIER_nondet_u32() { return 0; }
28 | uint64_t __VERIFIER_nondet_u64() { return 0; }
29 | uintptr_t __VERIFIER_nondet_usize() { return 0; }
30 |
31 | int8_t __VERIFIER_nondet_i8() { return 0; }
32 | int16_t __VERIFIER_nondet_i16() { return 0; }
33 | int32_t __VERIFIER_nondet_i32() { return 0; }
34 | int64_t __VERIFIER_nondet_i64() { return 0; }
35 | intptr_t __VERIFIER_nondet_isize() { return 0; }
36 |
37 | float __VERIFIER_nondet_f32() { return 0; }
38 | double __VERIFIER_nondet_f64() { return 0; }
39 |
--------------------------------------------------------------------------------
/verification-annotations/lib/smack-rust.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define mk_signed_type(size) int##size##_t
5 | #define mk_unsigned_type(size) uint##size##_t
6 |
7 | #define mk_signed_min(size) INT##size##_MIN
8 | #define mk_signed_max(size) INT##size##_MAX
9 | #define mk_unsigned_min(size) 0
10 | #define mk_unsigned_max(size) UINT##size##_MAX
11 |
12 | #define mk_smack_signed_nondet(size) __SMACK_nondet_i##size
13 | #define mk_smack_unsigned_nondet(size) __SMACK_nondet_u##size
14 | #define mk_smack_nondet_decl(size) \
15 | mk_signed_type(size) mk_smack_signed_nondet(size)(void); \
16 | mk_unsigned_type(size) mk_smack_unsigned_nondet(size)(void);
17 |
18 | #define mk_smack_nondet_def(size) \
19 | mk_signed_type(size) __VERIFIER_nondet_i##size(void) { \
20 | mk_signed_type(size) ret = mk_smack_signed_nondet(size)(); \
21 | if (ret < mk_signed_min(size) || ret > mk_signed_max(size)) \
22 | abort(); \
23 | return ret; \
24 | } \
25 | mk_unsigned_type(size) __VERIFIER_nondet_u##size(void) { \
26 | mk_unsigned_type(size) ret = mk_smack_unsigned_nondet(size)(); \
27 | if (ret < mk_unsigned_min(size) || ret > mk_unsigned_max(size)) \
28 | abort(); \
29 | return ret; \
30 | }
31 |
32 | #define mk_dummy_int_nondet_def(size) \
33 | mk_signed_type(size) __VERIFIER_nondet_i##size(void) { \
34 | return *((mk_signed_type(size) *)malloc(sizeof(mk_signed_type(size)))); \
35 | } \
36 | mk_unsigned_type(size) __VERIFIER_nondet_u##size(void) { \
37 | return *( \
38 | (mk_unsigned_type(size) *)malloc(sizeof(mk_unsigned_type(size)))); \
39 | }
40 |
41 | #define mk_dummy_fp_nondet_def(ty) \
42 | ty __VERIFIER_nondet_##ty(void) { return *((ty *)malloc(sizeof(ty))); }
43 |
44 | #if CARGO_BUILD
45 | mk_dummy_int_nondet_def(8) mk_dummy_int_nondet_def(16)
46 | mk_dummy_int_nondet_def(32) mk_dummy_int_nondet_def(64)
47 | mk_dummy_fp_nondet_def(float)
48 | mk_dummy_fp_nondet_def(double) void __VERIFIER_assert(int x) {}
49 | void __VERIFIER_assume(int x) {}
50 | #else
51 | mk_smack_nondet_decl(8) mk_smack_nondet_decl(16) mk_smack_nondet_decl(32)
52 | mk_smack_nondet_decl(64) mk_smack_nondet_def(8) mk_smack_nondet_def(16)
53 | mk_smack_nondet_def(32) mk_smack_nondet_def(64)
54 | #endif
55 |
--------------------------------------------------------------------------------
/verification-annotations/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #![feature(cstring_from_vec_with_nul)]
10 | #![cfg_attr(not(feature = "std"), no_std)]
11 |
12 | // Traits for creating symbolic/abstract values
13 | pub mod traits;
14 | pub mod verifier;
15 |
16 | #[cfg(feature = "std")]
17 | pub mod utils {
18 | pub trait UnwrapOrReject {
19 | type Wrapped;
20 | fn unwrap_or_reject(self) -> Self::Wrapped;
21 | }
22 |
23 | impl UnwrapOrReject for Result {
24 | type Wrapped = T;
25 | fn unwrap_or_reject(self) -> Self::Wrapped {
26 | match self {
27 | Ok(x) => x,
28 | Err(_) => crate::verifier::reject(),
29 | }
30 | }
31 | }
32 |
33 | impl UnwrapOrReject for Option {
34 | type Wrapped = T;
35 | fn unwrap_or_reject(self) -> Self::Wrapped {
36 | match self {
37 | Some(x) => x,
38 | None => crate::verifier::reject(),
39 | }
40 | }
41 | }
42 | }
43 |
44 | // `use verfication_annotations::prelude::*`
45 | pub mod prelude {
46 | pub use crate::traits::*;
47 | #[cfg(feature = "std")]
48 | pub use crate::utils::*;
49 | pub use crate::verifier;
50 |
51 | // Macros
52 | pub use crate::verifier::assert as verifier_assert;
53 | pub use crate::verifier::assert_eq as verifier_assert_eq;
54 | pub use crate::verifier::assert_ne as verifier_assert_ne;
55 | pub use crate::verifier::assume as verifier_assume;
56 | pub use crate::verifier::unreachable as verifier_unreachable;
57 | }
58 |
59 | // At the moment, the cargo-verify script does not support
60 | // use of a separate test directory so, for now, we put
61 | // the tests here.
62 | #[cfg(all(test, feature = "std"))]
63 | mod tests;
64 |
--------------------------------------------------------------------------------
/verification-annotations/src/tests.rs:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////
2 | // Several variations on a theme to test failing variants
3 | ////////////////////////////////////////////////////////////////
4 |
5 | use crate::prelude::*;
6 |
7 | use crate::verifier::assert;
8 |
9 | #[cfg_attr(not(feature = "verifier-crux"), test)]
10 | #[cfg_attr(feature = "verifier-crux", crux_test)]
11 | fn t0() {
12 | let a: u32 = verifier::AbstractValue::abstract_value();
13 | let b: u32 = verifier::AbstractValue::abstract_value();
14 | verifier::assume(4 <= a && a <= 7);
15 | verifier::assume(5 <= b && b <= 8);
16 |
17 | #[cfg(not(any(
18 | feature = "verifier-crux",
19 | feature = "verifier-seahorn",
20 | feature = "verifier-smack"
21 | )))]
22 | if verifier::is_replay() {
23 | eprintln!("Test values: a = {}, b = {}", a, b)
24 | }
25 |
26 | let r = a * b;
27 | assert!(20 <= r && r <= 56);
28 | }
29 |
30 | #[cfg_attr(not(feature = "verifier-crux"), test)]
31 | #[cfg_attr(feature = "verifier-crux", crux_test)]
32 | fn t1() {
33 | let a: u32 = verifier::AbstractValue::abstract_value();
34 | let b: u32 = verifier::AbstractValue::abstract_value();
35 | verifier::assume(4 <= a && a <= 7);
36 | verifier::assume(5 <= b && b <= 8);
37 | let r = a * b;
38 | assert!(20 <= r && r <= 56);
39 | }
40 |
41 | #[cfg_attr(not(feature = "verifier-crux"), test)]
42 | #[cfg_attr(feature = "verifier-crux", crux_test)]
43 | fn t2() {
44 | #[cfg(not(feature = "verifier-crux"))]
45 | verifier::expect(Some("multiply with overflow"));
46 |
47 | let a: u32 = verifier::AbstractValue::abstract_value();
48 | let b: u32 = verifier::AbstractValue::abstract_value();
49 | let r = a * b;
50 | verifier::assume(4 <= a && a <= 7);
51 | verifier::assume(5 <= b && b <= 8);
52 | assert!(20 <= r && r <= 56);
53 | }
54 |
55 | #[cfg_attr(not(feature = "verifier-crux"), test)]
56 | #[cfg_attr(feature = "verifier-crux", crux_test)]
57 | fn t3() {
58 | #[cfg(not(feature = "verifier-crux"))]
59 | verifier::expect(Some("assertion failed"));
60 |
61 | let a: u32 = verifier::AbstractValue::abstract_value();
62 | let b: u32 = verifier::AbstractValue::abstract_value();
63 | verifier::assume(4 <= a && a <= 7);
64 | verifier::assume(5 <= b && b <= 8);
65 | let r = a * b;
66 | assert!(20 <= r && r < 56);
67 | }
68 |
69 | #[cfg_attr(not(feature = "verifier-crux"), test)]
70 | #[cfg_attr(feature = "verifier-crux", crux_test)]
71 | fn t4() {
72 | #[cfg(not(feature = "verifier-crux"))]
73 | verifier::expect(None);
74 |
75 | let a: u32 = verifier::AbstractValue::abstract_value();
76 | let b: u32 = verifier::AbstractValue::abstract_value();
77 | verifier::assume(4 <= a && a <= 7);
78 | verifier::assume(5 <= b && b <= 8);
79 | let r = a * b;
80 | assert!(20 <= r && r < 56);
81 | }
82 |
83 | #[cfg_attr(not(feature = "verifier-crux"), test)]
84 | #[cfg_attr(feature = "verifier-crux", crux_test)]
85 | fn t5() {
86 | let a: u32 = verifier::AbstractValue::abstract_value();
87 | let b: u32 = verifier::AbstractValue::abstract_value();
88 | verifier::assume(a <= 1000000); // avoid overflow
89 | verifier::assume(b <= 1000000);
90 | verifier::assert_eq!(a + b, b + a);
91 | verifier::assert_ne!(a, a + 1);
92 | }
93 |
94 | // KLEE-only test of get_concrete_value and is_symbolic
95 | #[cfg(feature = "verifier-klee")]
96 | #[test]
97 | fn concrete1() {
98 | let a: u32 = verifier::AbstractValue::abstract_value();
99 | verifier::assume(a <= 100); // avoid overflow
100 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
101 |
102 | let b = verifier::VerifierNonDet::get_concrete_value(a);
103 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
104 | verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
105 | verifier::assert!(b <= 100);
106 |
107 | // There is no expectation that each call to get_concrete_value
108 | // will produce a different result and, on KLEE, it can
109 | // produce the same result unless you add assumptions/branches
110 | // to avoid repetition.
111 | // This test is commented out because we don't want to insist
112 | // on one behavior or another.
113 | // let c = verifier::VerifierNonDet::get_concrete_value(a);
114 | // verifier::assert_eq!(b, c);
115 | }
116 |
117 | // KLEE-only test of concretize
118 | #[cfg(feature = "verifier-klee")]
119 | #[test]
120 | fn concrete2() {
121 | let a: u32 = verifier::AbstractValue::abstract_value();
122 | verifier::assume(a <= 10); // limit number of distinct solutions
123 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
124 |
125 | let b = verifier::concretize(a);
126 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
127 | verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
128 | verifier::assert!(b <= 10);
129 | }
130 |
131 | // KLEE-only test of sample
132 | #[cfg(feature = "verifier-klee")]
133 | #[test]
134 | fn concrete3() {
135 | let a: u32 = verifier::AbstractValue::abstract_value();
136 | verifier::assume(a <= 1_000_000_000); // allow a huge number of solutions
137 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
138 |
139 | let b = verifier::sample(10, a); // consider only 10 of the possible solutions for a
140 | verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
141 | verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
142 | verifier::assert!(b <= 1_000_000_000);
143 | }
144 |
145 | /// Test of verifier_nondet_bytes
146 | #[cfg_attr(not(feature = "verifier-crux"), test)]
147 | #[cfg_attr(feature = "verifier-crux", crux_test)]
148 | fn bytes() {
149 | let a = verifier::verifier_nondet_bytes(8);
150 | for i in &a {
151 | verifier::assume(*i == 42);
152 | }
153 | if verifier::is_replay() {
154 | println!("{:?}", a);
155 | }
156 | verifier::assert_eq!(a.len(), 8);
157 | verifier::assert_ne!(a[2], 0u8);
158 | verifier::assert_eq!(a[3], 42u8);
159 | }
160 |
161 | /// Test of verifier_nondet_cstring
162 | #[cfg_attr(not(feature = "verifier-crux"), test)]
163 | #[cfg_attr(feature = "verifier-crux", crux_test)]
164 | fn cstring() {
165 | let a = verifier::verifier_nondet_cstring(8);
166 |
167 | if verifier::is_replay() {
168 | println!("{:?}", a);
169 | }
170 |
171 | // force string to be plain ASCII - to keep things simple
172 | for i in a.as_bytes() {
173 | // note: this code suffers from a path explosion and
174 | // would benefit from using verifier::coherent!
175 | // We will not do that though because the goal is to
176 | // test this feature in isolation.
177 | verifier::assume(i.is_ascii_alphabetic());
178 | }
179 |
180 | for i in a.as_bytes() {
181 | verifier::assert!(i.is_ascii());
182 | // this assertion would fail
183 | // verifier::assert!(i.is_ascii_digit());
184 | }
185 | }
186 |
187 | /// Test of verifier_nondet_ascii_string
188 | #[cfg_attr(not(feature = "verifier-crux"), test)]
189 | #[cfg_attr(feature = "verifier-crux", crux_test)]
190 | fn string_ok() {
191 | let a = verifier::verifier_nondet_ascii_string(6);
192 |
193 | if verifier::is_replay() {
194 | println!("{:?}", a);
195 | }
196 |
197 | // force string to be a legal int
198 | for i in a.as_bytes() {
199 | verifier::assume(('0'..='3').contains(&(*i as char)))
200 | }
201 |
202 | let i: u32 = a.parse().unwrap();
203 | verifier::assert!(i <= 333_333);
204 | }
205 |
206 | /// Test of verifier_nondet_ascii_stringg
207 | #[cfg_attr(not(feature = "verifier-crux"), test)]
208 | #[cfg_attr(feature = "verifier-crux", crux_test)]
209 | fn string_should_fail() {
210 | verifier::expect(Some("assertion failed"));
211 | let a = verifier::verifier_nondet_ascii_string(6);
212 |
213 | if verifier::is_replay() {
214 | println!("{:?}", a);
215 | }
216 |
217 | // force string to be a legal int
218 | for i in a.as_bytes() {
219 | verifier::assume(('0'..='3').contains(&(*i as char)))
220 | }
221 |
222 | let i: u32 = a.parse().unwrap();
223 | verifier::assert!(i <= 222_222);
224 | }
225 |
226 | ////////////////////////////////////////////////////////////////
227 | // End
228 | ////////////////////////////////////////////////////////////////
229 |
--------------------------------------------------------------------------------
/verification-annotations/src/traits.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | // There are three different styles of interface (that we are aware of):
10 | // - symbolic(desc) - takes a string argument 'desc' - optionally used in counterexamples
11 | // - verifier_nondet(c) - takes a concrete argument 'c' that is ignored
12 | // - abstract_value() - no arguments
13 | //
14 | // For some (limited) amount of compatibility, we implement all three
15 |
16 | use crate::verifier::assume;
17 |
18 | /// Create a non-deterministic value with the same type as the argument
19 | ///
20 | /// The argument does not influence the result of the function.
21 | ///
22 | /// This is intended to be compatible with SMACK
23 | pub trait VerifierNonDet {
24 | fn verifier_nondet(self) -> Self;
25 |
26 | #[cfg(feature = "verifier-klee")]
27 | /// Obtain a concrete value satisfying the constraints
28 | /// currently in force for the expression.
29 | ///
30 | /// Not guaranteed to produce different (or the same) value
31 | /// if called repeatedly.
32 | /// (Use assumptions or if-statements to produce different results
33 | /// each time.)
34 | ///
35 | /// This function may not be implementable with other
36 | /// verifiers so it should be used with caution.
37 | fn get_concrete_value(x: Self) -> Self;
38 |
39 | #[cfg(feature = "verifier-klee")]
40 | /// Test whether a value is concrete or symbolic
41 | ///
42 | /// Values are guaranteed to be concrete if they are derived
43 | /// from concrete values, literal constants or
44 | /// calls to `get_concrete_value`.
45 | fn is_symbolic(x: Self) -> bool;
46 | }
47 |
48 | pub trait AbstractValue: Sized {
49 | /// Create an abstract value of type `Self`
50 | fn abstract_value() -> Self;
51 |
52 | /// Create an abstract value satisfying a predicate `F`
53 | fn abstract_where bool>(f: F) -> Self {
54 | let x = Self::abstract_value();
55 | assume(f(&x));
56 | x
57 | }
58 | }
59 |
60 | /// Create a symbolic value of type `Self` and with
61 | /// documentation name `desc`
62 | ///
63 | /// This is intended to be compatible with Crux-MIR.
64 | pub trait Symbolic: Sized {
65 | fn symbolic(desc: &'static str) -> Self;
66 |
67 | fn symbolic_where bool>(desc: &'static str, f: F) -> Self {
68 | let x = Self::symbolic(desc);
69 | assume(f(&x));
70 | x
71 | }
72 | }
73 |
74 | /////////////////////////////////////////////////////////////////
75 | // End
76 | /////////////////////////////////////////////////////////////////
77 |
--------------------------------------------------------------------------------
/verification-annotations/src/verifier/crux.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | /////////////////////////////////////////////////////////////////
10 | // FFI wrapper for Crux-mir static simulator tool
11 | /////////////////////////////////////////////////////////////////
12 |
13 | use crate::traits::*;
14 |
15 | impl VerifierNonDet for T {
16 | fn verifier_nondet(self) -> Self {
17 | T::abstract_value()
18 | }
19 | }
20 |
21 | impl AbstractValue for T {
22 | fn abstract_value() -> Self {
23 | // We assume the string argument is just for reporting to the user, and
24 | // doesn't affect the results.
25 | let r: T = crucible::Symbolic::symbolic("");
26 | r
27 | }
28 | }
29 |
30 | impl Symbolic for T {
31 | fn symbolic(desc: &'static str) -> Self {
32 | let r: T = crucible::Symbolic::symbolic(desc);
33 | r
34 | }
35 | }
36 |
37 | /// Assume that condition `cond` is true
38 | ///
39 | /// Any paths found must satisfy this assumption.
40 | pub fn assume(cond: bool) {
41 | crucible::crucible_assume!(cond)
42 | }
43 |
44 | /// Reject the current execution with a verification failure.
45 | ///
46 | /// In almost all circumstances, `report_error` should
47 | /// be used instead because it generates an error message.
48 | pub fn abort() {
49 | crucible::crucible_assert!(false)
50 | }
51 |
52 | /// Reject the current execution path with a verification success.
53 | /// This is equivalent to `assume(false)`
54 | /// and the opposite of `report_error(...)`.
55 | ///
56 | /// Typical usage is in generating symbolic values when the value
57 | /// does not meet some criteria.
58 | pub fn reject() -> ! {
59 | crucible::crucible_assume!(false);
60 | panic!("should have been rejected!");
61 | }
62 |
63 | /// Detect whether the program is being run symbolically in KLEE
64 | /// or being replayed using the kleeRuntest runtime.
65 | ///
66 | /// This is used to decide whether to display the values of
67 | /// variables that may be either symbolic or concrete.
68 | pub fn is_replay() -> bool {
69 | panic!("crux doesn't support replay")
70 | }
71 |
72 | /// Reject the current execution with a verification failure
73 | /// and an error message.
74 | pub fn report_error(message: &str) {
75 | crucible::crucible_assert!(false, "VERIFIER: ERROR: {}", message);
76 | }
77 |
78 | /// Declare that failure is the expected behaviour
79 | pub fn expect_raw(_msg: &str) {
80 | panic!("not implemented")
81 | }
82 |
83 | /// Declare that failure is the expected behaviour
84 | pub fn expect(_msg: Option<&str>) {
85 | panic!("not implemented")
86 | }
87 |
88 | #[macro_export]
89 | macro_rules! assert {
90 | ($cond:expr) => {
91 | $crate::crucible::crucible_assert!(
92 | $cond,
93 | "VERIFIER: assertion failed: {}",
94 | stringify!($cond)
95 | );
96 | }; // ($cond:expr,) => { ... };
97 | // ($cond:expr, $($arg:tt)+) => { ... };
98 | }
99 |
100 | #[macro_export]
101 | macro_rules! assert_eq {
102 | ($left:expr, $right:expr) => {
103 | $crate::verifier::assert!(($left) == ($right));
104 | }; // ($left:expr, $right:expr,) => { ... };
105 | // ($left:expr, $right:expr, $($arg:tt)+) => { ... };
106 | }
107 |
108 | #[macro_export]
109 | macro_rules! assert_ne {
110 | ($left:expr, $right:expr) => {
111 | $crate::verifier::assert!(($left) != ($right));
112 | }; // ($left:expr, $right:expr,) => { ... };
113 | // ($left:expr, $right:expr, $($arg:tt)+) => { ... };
114 | }
115 |
116 | /////////////////////////////////////////////////////////////////
117 | // End
118 | /////////////////////////////////////////////////////////////////
119 |
--------------------------------------------------------------------------------
/verification-annotations/src/verifier/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #[cfg(feature = "std")]
10 | use std::default::Default;
11 |
12 | #[cfg(feature = "std")]
13 | use std::ffi::CString;
14 |
15 | // Traits for creating symbolic/abstract values
16 | #[cfg(feature = "verifier-klee")]
17 | mod klee;
18 | #[cfg(feature = "verifier-klee")]
19 | pub use klee::*;
20 |
21 | #[cfg(feature = "verifier-crux")]
22 | pub extern crate crucible;
23 | #[cfg(feature = "verifier-crux")]
24 | mod crux;
25 | #[cfg(feature = "verifier-crux")]
26 | pub use crux::*;
27 |
28 | #[cfg(feature = "verifier-seahorn")]
29 | mod seahorn;
30 | #[cfg(feature = "verifier-seahorn")]
31 | pub use seahorn::*;
32 |
33 | #[cfg(feature = "verifier-smack")]
34 | mod smack;
35 | #[cfg(feature = "verifier-smack")]
36 | pub use smack::*;
37 |
38 | #[cfg(feature = "std")]
39 | /// Allocate a symbolic vector of bytes
40 | pub fn verifier_nondet_bytes(n: usize) -> Vec {
41 | let mut v: Vec = Vec::with_capacity(n);
42 | v.resize_with(n, || VerifierNonDet::verifier_nondet(0u8));
43 | return v;
44 | }
45 |
46 | #[cfg(feature = "std")]
47 | /// Allocate a symbolic CString
48 | pub fn verifier_nondet_cstring(size_excluding_null: usize) -> CString {
49 | let mut r = verifier_nondet_bytes(size_excluding_null + 1);
50 | for i in 0..size_excluding_null {
51 | assume(r[i] != 0u8);
52 | }
53 | r[size_excluding_null] = 0u8;
54 | unsafe { CString::from_vec_with_nul_unchecked(r) }
55 | }
56 |
57 | #[cfg(feature = "std")]
58 | /// Allocate a symbolic ASCII String
59 | /// (ASCII strings avoid the complexity of UTF-8)
60 | pub fn verifier_nondet_ascii_string(n: usize) -> String {
61 | let r = verifier_nondet_bytes(n);
62 | for i in 0..n {
63 | assume(r[i] != 0u8);
64 | assume(r[i].is_ascii());
65 | }
66 | match String::from_utf8(r) {
67 | Ok(r) => r,
68 | Err(_) => reject(),
69 | }
70 | }
71 |
72 | impl AbstractValue for T {
73 | fn abstract_value() -> Self {
74 | Self::verifier_nondet(Self::default())
75 | }
76 | }
77 |
78 | impl Symbolic for T {
79 | fn symbolic(_desc: &'static str) -> Self {
80 | Self::verifier_nondet(Self::default())
81 | }
82 | }
83 |
84 | // Macros
85 |
86 | #[macro_export]
87 | macro_rules! assert {
88 | ($cond:expr,) => { $crate::verifier::assert!($cond) };
89 | ($cond:expr) => { $crate::verifier::assert!($cond, "assertion failed: {}", stringify!($cond)) };
90 | ($cond:expr, $($arg:tt)+) => {{
91 | if ! $cond {
92 | #[cfg(not(feature = "verifier-smack"))]
93 | {
94 | let message = format!($($arg)+);
95 | eprintln!("VERIFIER: panicked at '{}', {}:{}:{}",
96 | message,
97 | std::file!(), std::line!(), std::column!());
98 | }
99 | $crate::verifier::abort();
100 | }
101 | }}
102 | }
103 |
104 | #[macro_export]
105 | macro_rules! assert_eq {
106 | ($left:expr, $right:expr) => {{
107 | let left = $left;
108 | let right = $right;
109 | $crate::verifier::assert!(
110 | left == right,
111 | "assertion failed: `(left == right)` \
112 | \n left: `{:?}`,\n right: `{:?}`",
113 | left,
114 | right)
115 | }};
116 | ($left:expr, $right:expr, $fmt:tt $($arg:tt)*) => {{
117 | let left = $left;
118 | let right = $right;
119 | $crate::verifier::assert!(
120 | left == right,
121 | concat!(
122 | "assertion failed: `(left == right)` \
123 | \n left: `{:?}`, \n right: `{:?}`: ", $fmt),
124 | left, right $($arg)*);
125 | }};
126 | }
127 |
128 | #[macro_export]
129 | macro_rules! assert_ne {
130 | ($left:expr, $right:expr) => {{
131 | let left = $left;
132 | let right = $right;
133 | $crate::verifier::assert!(
134 | left != right,
135 | "assertion failed: `(left != right)` \
136 | \n left: `{:?}`,\n right: `{:?}`",
137 | left,
138 | right)
139 | }};
140 | ($left:expr, $right:expr, $fmt:tt $($arg:tt)*) => {{
141 | let left = $left;
142 | let right = $right;
143 | $crate::verifier::assert!(
144 | left != right,
145 | concat!(
146 | "assertion failed: `(left != right)` \
147 | \n left: `{:?}`, \n right: `{:?}`: ", $fmt),
148 | left, right $($arg)*);
149 | }};
150 | }
151 |
152 | #[macro_export]
153 | macro_rules! unreachable {
154 | () => {
155 | $crate::report_error("unreachable assertion was reached");
156 | };
157 | }
158 |
159 | pub use crate::assert;
160 | pub use crate::assert_eq;
161 | pub use crate::assert_ne;
162 | pub use crate::unreachable;
163 |
164 | #[cfg(feature = "verifier-klee")]
165 | pub use crate::coherent;
166 |
--------------------------------------------------------------------------------
/verification-annotations/src/verifier/seahorn.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | /////////////////////////////////////////////////////////////////
10 | // FFI wrapper for SeaHorn symbolic execution tool
11 | /////////////////////////////////////////////////////////////////
12 |
13 | use std::convert::TryInto;
14 |
15 | pub use crate::traits::*;
16 |
17 | extern "C" {
18 | fn __VERIFIER_error() -> !;
19 | fn __VERIFIER_assume(pred: i32);
20 | }
21 |
22 | #[no_mangle]
23 | fn spanic() -> ! {
24 | abort();
25 | }
26 |
27 | /// Reject the current execution with a verification failure.
28 | ///
29 | /// In almost all circumstances, `report_error` should
30 | /// be used instead because it generates an error message.
31 | pub fn abort() -> ! {
32 | unsafe {
33 | __VERIFIER_error();
34 | }
35 | }
36 |
37 | /// Assume that condition `cond` is true
38 | ///
39 | /// Any paths found must satisfy this assumption.
40 | pub fn assume(pred: bool) {
41 | unsafe {
42 | __VERIFIER_assume(pred as i32);
43 | }
44 | }
45 |
46 | /// Reject the current execution path with a verification success.
47 | /// This is equivalent to `assume(false)`
48 | /// and the opposite of `report_error(...)`.
49 | ///
50 | /// Typical usage is in generating symbolic values when the value
51 | /// does not meet some criteria.
52 | pub fn reject() -> ! {
53 | assume(false);
54 | panic!("Unreachable, should have been rejected!");
55 | }
56 |
57 | /// Detect whether the program is being run symbolically in KLEE
58 | /// or being replayed using the kleeRuntest runtime.
59 | ///
60 | /// This is used to decide whether to display the values of
61 | /// variables that may be either symbolic or concrete.
62 | pub fn is_replay() -> bool {
63 | // panic!("SeaHorn doesn't support replay.")
64 | false
65 | }
66 |
67 | /// Reject the current execution with a verification failure
68 | /// and an error message.
69 | pub fn report_error(message: &str) -> ! {
70 | // Mimic the format of klee_report_error
71 | // (We don't use klee_report_error because it is not
72 | // supported by the kleeRuntest library.)
73 | eprintln!("SEAHORN: ERROR:{}", message);
74 | abort();
75 | }
76 |
77 | /// Declare that failure is the expected behaviour
78 | pub fn expect_raw(msg: &str) {
79 | eprintln!("VERIFIER_EXPECT: {}", msg)
80 | }
81 |
82 | /// Declare that failure is the expected behaviour
83 | pub fn expect(msg: Option<&str>) {
84 | match msg {
85 | None => eprintln!("VERIFIER_EXPECT: should_panic"),
86 | Some(msg) => eprintln!("VERIFIER_EXPECT: should_panic(expected = \"{}\")", msg),
87 | }
88 | }
89 |
90 | macro_rules! make_nondet {
91 | ($typ:ty, $ext:ident, $v:expr) => {
92 | extern "C" {
93 | fn $ext() -> $typ;
94 | }
95 | impl VerifierNonDet for $typ {
96 | fn verifier_nondet(self) -> Self {
97 | unsafe { $ext() }
98 | }
99 | }
100 | };
101 | }
102 |
103 | make_nondet!(u8, __VERIFIER_nondet_u8, 0);
104 | make_nondet!(u16, __VERIFIER_nondet_u16, 0);
105 | make_nondet!(u32, __VERIFIER_nondet_u32, 0);
106 | make_nondet!(u64, __VERIFIER_nondet_u64, 0);
107 | make_nondet!(usize, __VERIFIER_nondet_usize, 0);
108 |
109 | make_nondet!(i8, __VERIFIER_nondet_i8, 0);
110 | make_nondet!(i16, __VERIFIER_nondet_i16, 0);
111 | make_nondet!(i32, __VERIFIER_nondet_i32, 0);
112 | make_nondet!(i64, __VERIFIER_nondet_i64, 0);
113 | make_nondet!(isize, __VERIFIER_nondet_isize, 0);
114 |
115 | make_nondet!(f32, __VERIFIER_nondet_f32, 0.0);
116 | make_nondet!(f64, __VERIFIER_nondet_f64, 0.0);
117 |
118 | macro_rules! make_nondet_ne_bytes {
119 | ($typ:ty) => {
120 | impl VerifierNonDet for $typ {
121 | fn verifier_nondet(self) -> Self {
122 | let mut bytes = vec![0u8; std::mem::size_of::<$typ>()];
123 | for i in 0..bytes.len() {
124 | unsafe {
125 | bytes[i] = __VERIFIER_nondet_u8();
126 | }
127 | }
128 | Self::from_ne_bytes(bytes[..].try_into().unwrap())
129 | }
130 | }
131 | };
132 | }
133 |
134 | make_nondet_ne_bytes!(u128);
135 | make_nondet_ne_bytes!(i128);
136 |
137 | impl VerifierNonDet for bool {
138 | fn verifier_nondet(self) -> Self {
139 | let c = u8::verifier_nondet(0u8);
140 | assume(c == 0 || c == 1);
141 | c == 1
142 | }
143 | }
144 |
145 | /////////////////////////////////////////////////////////////////
146 | // End
147 | /////////////////////////////////////////////////////////////////
148 |
--------------------------------------------------------------------------------
/verification-annotations/src/verifier/smack.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The Propverify authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | /////////////////////////////////////////////////////////////////
10 | // FFI wrapper for SMACK symbolic execution tool
11 | /////////////////////////////////////////////////////////////////
12 |
13 | use std::convert::TryInto;
14 |
15 | pub use crate::traits::*;
16 | use std::alloc::Layout;
17 |
18 | extern "C" {
19 | fn __VERIFIER_assert(pred: i32) -> !;
20 | fn __VERIFIER_assume(pred: i32);
21 | pub fn malloc(size: usize) -> *mut u8;
22 | pub fn free(ptr: *mut u8);
23 | fn memset(ptr: *mut u8, ch: i32, count: usize);
24 | fn realloc(ptr: *mut u8, new_size: usize) -> *mut u8;
25 | }
26 | #[no_mangle]
27 | fn spanic() -> ! {
28 | abort();
29 | }
30 |
31 | /// Reject the current execution with a verification failure.
32 | ///
33 | /// In almost all circumstances, `report_error` should
34 | /// be used instead because it generates an error message.
35 | pub fn abort() -> ! {
36 | unsafe {
37 | __VERIFIER_assert(0);
38 | }
39 | }
40 |
41 | /// Assume that condition `cond` is true
42 | ///
43 | /// Any paths found must satisfy this assumption.
44 | pub fn assume(pred: bool) {
45 | unsafe {
46 | __VERIFIER_assume(pred as i32);
47 | }
48 | }
49 |
50 | /// Reject the current execution path with a verification success.
51 | /// This is equivalent to `assume(false)`
52 | /// and the opposite of `report_error(...)`.
53 | ///
54 | /// Typical usage is in generating symbolic values when the value
55 | /// does not meet some criteria.
56 | pub fn reject() -> ! {
57 | assume(false);
58 | panic!("Unreachable, should have been rejected!");
59 | }
60 |
61 | /// Detect whether the program is being run symbolically in KLEE
62 | /// or being replayed using the kleeRuntest runtime.
63 | ///
64 | /// This is used to decide whether to display the values of
65 | /// variables that may be either symbolic or concrete.
66 | pub fn is_replay() -> bool {
67 | // panic!("SMACK doesn't support replay.")
68 | false
69 | }
70 |
71 | /// Reject the current execution with a verification failure
72 | /// and an error message.
73 | pub fn report_error(message: &str) -> ! {
74 | // Mimic the format of klee_report_error
75 | // (We don't use klee_report_error because it is not
76 | // supported by the kleeRuntest library.)
77 | eprintln!("SMACK: ERROR:{}", message);
78 | abort();
79 | }
80 |
81 | /// Declare that failure is the expected behaviour
82 | pub fn expect_raw(msg: &str) {
83 | eprintln!("VERIFIER_EXPECT: {}", msg)
84 | }
85 |
86 | /// Declare that failure is the expected behaviour
87 | pub fn expect(msg: Option<&str>) {
88 | match msg {
89 | None => eprintln!("VERIFIER_EXPECT: should_panic"),
90 | Some(msg) => eprintln!("VERIFIER_EXPECT: should_panic(expected = \"{}\")", msg),
91 | }
92 | }
93 |
94 | macro_rules! make_nondet {
95 | ($typ:ty, $ext:ident, $v:expr) => {
96 | extern "C" {
97 | fn $ext() -> $typ;
98 | }
99 | impl VerifierNonDet for $typ {
100 | fn verifier_nondet(self) -> Self {
101 | unsafe { $ext() }
102 | }
103 | }
104 | };
105 | }
106 |
107 | make_nondet!(u8, __VERIFIER_nondet_u8, 0);
108 | make_nondet!(u16, __VERIFIER_nondet_u16, 0);
109 | make_nondet!(u32, __VERIFIER_nondet_u32, 0);
110 | make_nondet!(u64, __VERIFIER_nondet_u64, 0);
111 | make_nondet!(usize, __VERIFIER_nondet_usize, 0);
112 |
113 | make_nondet!(i8, __VERIFIER_nondet_i8, 0);
114 | make_nondet!(i16, __VERIFIER_nondet_i16, 0);
115 | make_nondet!(i32, __VERIFIER_nondet_i32, 0);
116 | make_nondet!(i64, __VERIFIER_nondet_i64, 0);
117 | make_nondet!(isize, __VERIFIER_nondet_isize, 0);
118 |
119 | make_nondet!(f32, __VERIFIER_nondet_f32, 0.0);
120 | make_nondet!(f64, __VERIFIER_nondet_f64, 0.0);
121 |
122 | macro_rules! make_nondet_ne_bytes {
123 | ($typ:ty) => {
124 | impl VerifierNonDet for $typ {
125 | fn verifier_nondet(self) -> Self {
126 | let mut bytes = vec![0u8; std::mem::size_of::<$typ>()];
127 | for i in 0..bytes.len() {
128 | unsafe {
129 | bytes[i] = __VERIFIER_nondet_u8();
130 | }
131 | }
132 | Self::from_ne_bytes(bytes[..].try_into().unwrap())
133 | }
134 | }
135 | };
136 | }
137 |
138 | make_nondet_ne_bytes!(u128);
139 | make_nondet_ne_bytes!(i128);
140 |
141 | impl VerifierNonDet for bool {
142 | fn verifier_nondet(self) -> Self {
143 | let c = u8::verifier_nondet(0u8);
144 | assume(c == 0 || c == 1);
145 | c == 1
146 | }
147 | }
148 |
149 | /* Rust memory function models. */
150 | #[no_mangle]
151 | pub unsafe fn __smack_rust_std_alloc(layout: Layout) -> *mut u8 {
152 | __smack_rust_prim_alloc(layout.size(), layout.align())
153 | }
154 |
155 | #[no_mangle]
156 | pub unsafe fn __smack_rust_std_alloc_zeroed(layout: Layout) -> *mut u8 {
157 | __smack_rust_prim_alloc(layout.size(), layout.align())
158 | }
159 |
160 | #[no_mangle]
161 | pub unsafe fn __smack_rust_std_dealloc(ptr: *mut u8, layout: Layout) {
162 | __smack_rust_prim_dealloc(ptr, layout.size(), layout.align())
163 | }
164 |
165 | #[no_mangle]
166 | pub unsafe fn __smack_rust_std_realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
167 | __smack_rust_prim_realloc(ptr, layout.size(), layout.align(), new_size)
168 | }
169 |
170 | #[no_mangle]
171 | pub unsafe fn __smack_rust_prim_alloc(size: usize, _align: usize) -> *mut u8 {
172 | // Currently ignores alignment
173 | malloc(size)
174 | }
175 |
176 | #[no_mangle]
177 | pub unsafe fn __smack_rust_prim_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
178 | // Currently ignores alignment
179 | let result = malloc(size);
180 | memset(result, 0, size);
181 | result
182 | }
183 |
184 | #[no_mangle]
185 | pub unsafe fn __smack_rust_prim_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
186 | // Currently ignoring size and alignment
187 | free(ptr);
188 | }
189 |
190 | #[no_mangle]
191 | pub unsafe fn __smack_rust_prim_realloc(
192 | ptr: *mut u8,
193 | _old_size: usize,
194 | _align: usize,
195 | new_size: usize,
196 | ) -> *mut u8 {
197 | // Needs proper implementation of realloc
198 | // Ignores size and alignment
199 | realloc(ptr, new_size)
200 | }
201 |
202 | /////////////////////////////////////////////////////////////////
203 | // End
204 | /////////////////////////////////////////////////////////////////
205 |
--------------------------------------------------------------------------------