├── .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 | ![LLVM logo](https://www.llvm.org/img/DragonSmall.png){: 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 | --------------------------------------------------------------------------------