├── .travis.yml
├── CONTRIBUTE.md
├── COPYRIGHT
├── Cargo.toml
├── EXAMPLES.md
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── USAGE.md
├── build.rs
├── documents
├── ProjectPlan.md
├── RequirementsSpecificationDocument_v0.5.pdf
├── RequirementsSpecificationDocument_v1.0.pdf
├── RequirementsSpecificationDocument_v1.1.pdf
├── RequirementsSpecificationDocumentv1.2.pdf
├── RequirementsSpecificationDocumentv1.3.pdf
├── RiskManagementPlan.pdf
└── SoftwareArchitectureDesignDocument_v1.0.pdf
├── examples
└── README.md
├── scripts
└── travis-z3.sh
├── src
├── expression
│ └── mod.rs
├── lib.rs
├── parser
│ ├── expression_parser.lalrpop
│ ├── expression_parser.rs
│ └── mod.rs
├── reporting
│ └── mod.rs
├── smt_output
│ └── mod.rs
├── tests
│ ├── mod.rs
│ ├── system_tests.rs
│ ├── test_expression.rs
│ └── test_reporting.rs
└── weakest_precondition
│ ├── mod.rs
│ └── overflow.rs
└── tests
├── test_assert.rs
├── test_boolean_arithmetic.rs
├── test_conditionals.rs
├── test_conditions.rs
├── test_fail_invalid.rs
├── test_fail_valid.rs
├── test_signed.rs
└── test_unsigned.rs
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 |
3 | script: cargo test --lib
4 |
5 | rust:
6 | - nightly-2016-08-12
7 |
8 | env:
9 | global:
10 | secure: OinAZ2GfYnzFEB433bDd+G/DYUkDJLsPY/YRZEnkLRH5L9fK3UOe+FzkyZqa8GyCxDfVDV9yRyGfsRs2cIA3uXI0O3ZWGaEMjdhZODlvqdHQP86jdxZDZxjX+KSwOt9cZrB2rhmHImFzaZA+uS3TvFmbEIOvFknrMNU9od8KVqtcLxhHRmqkM7Zwd5oBVIsusGm0MLrXkRM621rCVutQVFxl5rYcD4/mYiPAew7xyWWzxyK+zBxJzgBLgWSe81HZmJKKEKihyWrkOLD8lGxHGFTS2zcASvwWEDGIbjbPvjzNBreG247RzO+TMPyBvRUmIHP+awn9ENJ08HB1hrfKKFdrM7+G89vOivWjs86n8PYSUAfWXuN8zVZ4KOYJr5L/sTKKP0JRcB2gicW2LY4kmQcVGjHrDnZjJg9qxR6wyDriDV5/jR+4Ko4M79HOAfmQnfrUeG2R6EF/TH+7b/+Qd2vofBZlCvCn+59raYsnMN0rjbq70WdCn+CFAHl2gc/UBk2clDjgnHiRAuzQ4kaBHeC/ieTB+jV44Dl7K9YtD0ce/Fkc0jRAnO30wIid73KYM9lZiY4/D3YULAQMXNhDlRLi+DPb2r+Tidem3dbwKGHIl6GKHJ8t2Chu8MFv51RYToevW7sWtn6RQZuBHTzbuTBqUPXaKaBeqU5g6jJjC+I=
11 |
12 | before_install:
13 | - mkdir -p ~/.local/bin
14 | - mkdir -p ~/.local/lib
15 | - export PATH=~/.local/bin:$PATH
16 | - export LD_LIBRARY_PATH=~/.local/lib:$LD_LIBRARY_PATH
17 | - chmod 700 ./scripts/travis-z3.sh
18 | - ./scripts/travis-z3.sh
19 |
20 | after_success: |
21 | [ $TRAVIS_BRANCH = master ] &&
22 | [ $TRAVIS_PULL_REQUEST = false ] &&
23 | cargo rustdoc -- --no-defaults --passes "collapse-docs" --passes "unindent-comments" --passes "strip-priv-imports" &&
24 | echo "" > target/doc/index.html &&
25 | sudo pip install ghp-import &&
26 | ghp-import -n target/doc &&
27 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
28 |
--------------------------------------------------------------------------------
/CONTRIBUTE.md:
--------------------------------------------------------------------------------
1 | # Contributing to rustproof
2 |
3 | If you're looking to contribute to rustproof, this document should help you understand the design structure of the project.
4 |
5 | Last updated Aug 24
6 |
7 | ## Overview
8 | A brief overview of the rustproof directory. More details on each module are in the next section.
9 |
10 | `src`
11 | : where the rustproof internals live.
12 |
13 | `tests`
14 | : system tests are located here. Testing is covered in more detail in the rustproof internals section.
15 |
16 | `examples`
17 | : examples that a new rustproof user can examine and run using `cargo build --example `
18 |
19 | `scripts`
20 | : currently the only script here is for Travis CI
21 |
22 | ## rustproof internals
23 | Within `src`, you'll find the following modules:
24 |
25 | ### `src/expression`
26 | This module is what creates rustproof's internal representations of logical expressions. Its functions are used in multiple places to create expressions from pre/post conditions, and from user written code (ultimately, from rust's MIR statements).
27 |
28 | Files: `mod.rs`
29 |
30 | ### `src/parser`
31 | The parser that uses generates `expression`s from a user's pre/post conditions. The `mod.rs` file has a function for checking the `#[condition]` attribute for errors, and a function for calling the parser.
32 |
33 | Some more details on the parser: `expression_parser.rs` is not intended to be modified manually. It is a LR(1) parser auto generated using the [LALRPOP](https://github.com/nikomatsakis/lalrpop) library. In order to modify the parser, you can modify the grammar rules in `expression_parser.lalrpop`.
34 |
35 | Files: `mod.rs`, `expression_parser.rs`, `expression_parser.lalrpop`
36 |
37 | ### `src/weakest_precondition`
38 | The brains behind generating a weakest precondition. This file generates the weakest precondition `wp` in `expression` format from MIR statements of the user's code. The `gen()` function performs a recursive depth-first search on the MIR control-flow graph, performing necessary replacements in `wp`'s expression in reverse order. For example, a post-condition `return: i32 == (x: i32 + 5i32)` would be the `wp` when `gen()` returns from the exit point of a function. If the next MIR statement prior to the exit point of the function is `return = (tmp1: i32)`, then a replacement occurs with the result being `tmp1: i32 == (x: i32 + 5i32)`. This continues until all MIR statements are read, ending with the first MIR statement of the function.
39 |
40 | Additionally there is the file `overflow.rs`: this file contains functions for overflow checking. If an expression contains the binary operator `signed add`, then an additional set of expressions is added onto `wp` to check for overflow.
41 |
42 | Files: `mod.rs`, `overflow.rs`
43 |
44 | ### `src/smt_output`
45 | This module translates `wp` from the internal `expression` format to SMT-lib format that is used by the SMT solver Z3. It then sends the final expression to [libsmt.rs](https://github.com/Rust-Proof/libsmt.rs), which runs Z3 in a child process, and returns any relevant information to the user.
46 |
47 | Files: `mod.rs`
48 |
49 | ### `src/reporting`
50 | rustproof's internal reporting module. This allows developers to throw meaningful rustproof warnings and errors to the user without exposing them to unhelpful rustproof internals. The macros are `rp_warn!()` and `rp_error!()`.
51 |
52 | Files: `mod.rs`
53 |
54 | ### `src/tests`
55 | This is where unit tests live, as well as where system tests are called from. Unit tests for most modules, namely `weakest_precondition`, are not only difficult to do (such as creating MIR stubs) but are also redundant with thorough system tests. `system_tests.rs` creates child processes that run the system tests located in the root directory's `tests` folder. Each function in a system test must begin with `valid` or `invalid` to correspond with their expected return, and is compared with their actual output to see if the test fails or passes. While this method currently works, it does not work with versions of rust nightly after 2016-08-11. Ultimately this method of system testing must change.
56 |
57 | Files: `mod.rs`, `system_tests.rs`, `test_expression.rs`
58 |
59 | ### `lib.rs`
60 | This file is the first point of entry for rustproof. It contains the `#[plugin_registrar]` attribute that rustc uses to identify compiler plugins. The `fn registrar()` is called once during compilation to register the used plugins, which in this case is the `MirPass`. `MirPass` is called once per user function (which may need to change in order to implement verification of function calls in user code). `MirPass` collects information about the function and its MIR statements, calls `gen()` from `weakest_preconditon`, and finishes with calling `gen_smtlib()` from `smt_output`.
61 |
--------------------------------------------------------------------------------
/COPYRIGHT:
--------------------------------------------------------------------------------
1 | The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | Michael Salter, Matthew Slocum, Vincent Schuster,
3 | Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
4 |
5 | Licensed under the Apache License, Version 2.0
6 | or the MIT
8 | license ,
9 | at your option. All files in the project carrying such
10 | notice may not be copied, modified, or distributed except
11 | according to those terms.
12 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rustproof"
3 | version = "0.1.0"
4 | authors = [
5 | "Matthew Slocum ",
6 | "Sami Sahli ",
7 | "Vincent Schuster ",
8 | "Matthew O'Brien ",
9 | "Michael Salter ",
10 | "Bradley Rasmussen ",
11 | "Drew Gohman "
12 | ]
13 | license = "Apache-2.0/MIT"
14 | description = "Compiler plugin to generate verification conditions from Rust code."
15 | repository = "https://github.com/Rust-Proof/rustproof"
16 | readme = "README.md"
17 | keywords = ["plugin", "smt", "verification", "solver", "satisfiability"]
18 | exclude = [
19 | "documents/*",
20 | "scripts/*",
21 | "build.rs",
22 | ".travis.yml",
23 | "src/parser/expression_parser.lalrpop",
24 | ]
25 |
26 | #build = "build.rs"
27 |
28 | [build-dependencies]
29 | lalrpop = "0.11.0"
30 |
31 | [dependencies]
32 | env_logger = "0.3.4"
33 | lalrpop-util = "0.11.0"
34 | rustproof-libsmt = "0.1.0"
35 | petgraph = "0.2.7"
36 |
37 | [lib]
38 | name = "rustproof"
39 | path = "src/lib.rs"
40 | plugin = true
41 |
--------------------------------------------------------------------------------
/EXAMPLES.md:
--------------------------------------------------------------------------------
1 | # Example Usages
2 |
3 | ## Integer Arithmetic with Overflow Checking
4 | ```
5 | // Proven to never overflow
6 | #[condition(pre="(x:i32 <= i32::MAX - 5:i32)", post="return:i32 == (x:i32 + 5:i32)")]
7 | fn add_five(x:i32) -> i32 {
8 | assert!(x <= 2147483647-5);
9 | x+5
10 | }
11 | ```
12 |
13 | ## Boolean Conditional
14 | ```
15 | // Proven to always return the NOT of the provided argument
16 | #[condition(pre="true", post="(x:bool==true IMPLIES return:bool==false) && (x:bool==false IMPLIES return:bool==true)")]
17 | fn boolean_not(x:bool) -> bool {
18 | if x == true {
19 | false
20 | } else {
21 | true
22 | }
23 | }
24 | ```
25 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2016 Rust-Proof
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 The Rust-Proof Developers
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rustproof
2 |
3 | [](https://travis-ci.org/Rust-Proof/rustproof)
4 |
5 | Rustproof is a compiler plugin for the Rust programming language. It generates verification conditions for functions with supplied preconditions(`P`) and postconditions(`Q`). That is, given a supplied postcondition on a function, rustproof uses [predicate transformer semantics](https://en.wikipedia.org/wiki/Predicate_transformer_semantics) to generate a weakest precondition(`WP(S, Q)`) from the postcondition and a body of statements(`S`). The verification condition `P->WP(S,Q)` is then checked for validity by a SMT solver ([z3](https://github.com/Z3Prover/z3)). This process results in a proof of function correctness.
6 |
7 | ## Dependencies
8 |
9 | * `rustc 1.12.0-nightly (2016-08-12)`.
10 |
11 | * [z3](https://github.com/Z3Prover/z3)
12 |
13 | Your installation of z3 needs to be in your PATH for rustproof to work.
14 |
15 | ## Supported Rust Language Features
16 |
17 | * Integer arithmetic
18 | * `isize` and `usize` are **unsupported**
19 | * Boolean expressions, variables, and literals
20 | * Assertions (integer/boolean)
21 | * `assert_eq!()` is **unsupported**
22 | * If statements
23 |
24 |
25 | ## Usage
26 |
27 | ### Including Rustproof in Your Project
28 |
29 | Add rustproof as a dependency in `Cargo.toml`
30 | ```toml
31 | [dependencies]
32 | rustproof = { git = "https://github.com/Rust-Proof/rustproof.git" }
33 | ```
34 |
35 | ### Using Rustproof
36 |
37 | `#![plugin(rustproof)]` is required in each file where rustproof is used. Typically this is placed at the beginning of a file.
38 |
39 | Rustproof uses a custom attribute `condition` to allow declaring pre/postconditions on functions.
40 |
41 | The attribute is supplied as:
42 | `#[condition(pre=" ", post=" ")]`
43 | and must be supplied before a function definition.
44 |
45 | See [USAGE](USAGE.md) for a detailed explanation of the attribute system.
46 |
47 | See [EXAMPLES](EXAMPLES.md) for example functions with condition attributes.
48 |
49 | Additionally, `#![plugin(rustproof(debug))]` prints out basic blocks of each function annotated with `#[condition(..)]`, as well as a step-by-step view of generating the verification condition.
50 |
51 |
52 | ## Contributors
53 | [Matthew Slocum][slocum]
54 | [Sami Sahli][sahli]
55 | [Vincent Schuster][schuster]
56 | [Michael Salter][salter]
57 | [Bradley Rasmussen][rasmussen]
58 | [Drew Gohman][gohman]
59 | [Matthew O'Brien][obrien]
60 |
61 | [slocum]:https://github.com/arc3x
62 | [sahli]:https://github.com/ssahli
63 | [schuster]:https://github.com/VSchuster
64 | [salter]:https://github.com/salterm
65 | [rasmussen]:https://github.com/bajr
66 | [gohman]:https://github.com/found101
67 | [obrien]:https://github.com/obriematt
68 |
69 | ## Reporting Issues
70 |
71 | Please report all issues on the github [issue tracker][issues].
72 |
73 | [issues]:https://github.com/Rust-Proof/rustproof/issues
74 |
75 |
76 | ## License
77 |
78 | Rustproof is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
79 |
80 | See [LICENSE-APACHE][1], [LICENSE-MIT][2], and [COPYRIGHT][3] for details.
81 |
82 | [1]:https://github.com/Rust-Proof/rustproof/blob/master/LICENSE-APACHE
83 | [2]:https://github.com/Rust-Proof/rustproof/blob/master/LICENSE-MIT
84 | [3]:https://github.com/Rust-Proof/rustproof/blob/master/COPYRIGHT
85 |
--------------------------------------------------------------------------------
/USAGE.md:
--------------------------------------------------------------------------------
1 | # To Use Rust-Proof
2 | Users should place the "condition" attribute tag above any function they should wish to test, along with a precondition and postcondition. If a user has a function "foo()" they can specify that Rust-Proof should analyze it like so:
3 |
4 | ```
5 | #condition[pre="P",post="Q"]
6 | foo() { ... }
7 | ```
8 |
9 | ...where "P" is a string containing the precondition, and "Q" is a string containing the postcondition. Neither string may be empty. If a user does not wish to specify either, they can enter the string "true".
10 |
11 | # How to format preconditions and postconditions
12 | Pre- and postconditions are made of boolean logical expressions. These expressions are composed of operands and operators. When all is said and done, the expressions should resolve to a boolean value.
13 |
14 | ## Operands
15 | Currently Rustproof will accept boolean literals (`true`, `false`), rust integer types (`u8`, `i64`, etc. excepting `isize` and `usize`), and variables of any of those types. Variables are named just like Rust identifiers, except for "return" which is a special variable only usable in the postcondition that refers to the return value of the function.
16 | Expressions can also be operands, if they resolve to the correct type. You must identify the type of your literal or variable with Rust-like syntax (except for "true" or "false"). Casting is not supported.
17 | In the precondition, the user can only reference variables that are arguments to the function in question. In the postcondition, one can reference arguments of the function and/or the special "return" variable, mentioned above.
18 |
19 | ## Operators
20 | There are three ways to think about operators: how many operands they work on, what types of operands they can work with, and what type an expression involving them resolves to. There are operator precendence rules (more on that below), but you may find that grouping expressions with parentheses is helpful.
21 |
22 | | Operator | Name | Number of operands | Operand type | Resolution type |
23 | |----------|-----------------------------|--------------------|---------------|-----------------|
24 | | + | Addition | 2 | Integer | Integer |
25 | | - | Subtraction | 2 | Integer | Integer |
26 | | * | Multiplication | 2 | Integer | Integer |
27 | | / | Division | 2 | Integer | Integer |
28 | | % | Modulus / Remainder | 2 | Integer | Integer |
29 | | \| | Bitwise Or | 2 | Any Primitive | Any Primitive |
30 | | & | Bitwise And | 2 | Any Primitive | Any Primitive |
31 | | ^ | Bitwise Exclusive Or / XOR | 2 | Any Primitive | Any Primitive |
32 | | << | Bitwise Left Shift | 2 | Any Primitive | Any Primitive |
33 | | >> | Bitwise Right Shift | 2 | Any Primitive | Any Primitive |
34 | | < | Less Than | 2 | Integer | Boolean |
35 | | <= | Less Than Or Equal | 2 | Integer | Boolean |
36 | | > | Greater Than | 2 | Integer | Boolean |
37 | | >= | Greater Than Or Equal | 2 | Integer | Boolean |
38 | | == | Equality | 2 | Integer | Boolean |
39 | | != | Inequality | 2 | Integer | Boolean |
40 | | && | Logical And | 2 | Boolean | Boolean |
41 | | \|\| | Logical Or | 2 | Boolean | Boolean |
42 | | AND | Conjunction | 2 | Boolean | Boolean |
43 | | OR | Disjunction | 2 | Boolean | Boolean |
44 | | XOR | Exclusive Disjunction / XOR | 2 | Boolean | Boolean |
45 | | IMPLIES | Implication | 2 | Boolean | Boolean |
46 | | => | Implication | 2 | Boolean | Boolean |
47 | | EQUIV | Equivalence | 2 | Boolean | Boolean |
48 | | <=> | Equivalence | 2 | Boolean | Boolean |
49 | | - | Negation | 1 | Integer | Integer |
50 | | ! | Bitwise Not | 1 | Any Primitive | Any Primitive |
51 | | NOT | Logical Negation | 1 | Boolean | Boolean |
52 |
53 | __Note__: The "&&", "||", and "!" operators are treated identically to the "AND", "OR", and "NOT" operators, respectively. "AND" and "OR" are added as conventions to make clear what is and is not meant to be a Rust-like expression, and "!" is overriden in Rust to be both logical and bitwise negation, since bitwise negation on a boolean primitive type amounts to the same thing. "IMPLIES" is a synonym for "=>", and "EQUIV" is a synonym for "<=>".
54 |
55 | __Operator precedence is as follows__ (more tightly binding first):
56 | ( )
57 | - (Unary), !, NOT
58 | *, /, %
59 | +, - (Binary)
60 | ^, &, |, <<, >>
61 | &&, ||
62 | AND, OR, XOR, IMPLIES, =>, EQUIV, <=>
63 |
64 | __Examples__:
65 |
66 | ```
67 | x: i32 > 5: i32
68 | ! true
69 | (y: u64 <= b: u64) OR ((b: u64 + 4: u64) > 8: u64)
70 | return: bool AND (!false)
71 | ```
72 |
73 | See [EXAMPLES](EXAMPLES.md) for example functions with condition attributes.
74 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | extern crate lalrpop;
2 |
3 | fn main() {
4 | lalrpop::process_root().unwrap();
5 | }
--------------------------------------------------------------------------------
/documents/ProjectPlan.md:
--------------------------------------------------------------------------------
1 | Click the link for the Project Plan task list:
2 |
3 | https://docs.google.com/spreadsheets/d/1YVubjOM2RETHxuXW5PW8P6Mw0DGE8zytd-30QftTTwg/pubhtml
4 |
--------------------------------------------------------------------------------
/documents/RequirementsSpecificationDocument_v0.5.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RequirementsSpecificationDocument_v0.5.pdf
--------------------------------------------------------------------------------
/documents/RequirementsSpecificationDocument_v1.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RequirementsSpecificationDocument_v1.0.pdf
--------------------------------------------------------------------------------
/documents/RequirementsSpecificationDocument_v1.1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RequirementsSpecificationDocument_v1.1.pdf
--------------------------------------------------------------------------------
/documents/RequirementsSpecificationDocumentv1.2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RequirementsSpecificationDocumentv1.2.pdf
--------------------------------------------------------------------------------
/documents/RequirementsSpecificationDocumentv1.3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RequirementsSpecificationDocumentv1.3.pdf
--------------------------------------------------------------------------------
/documents/RiskManagementPlan.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/RiskManagementPlan.pdf
--------------------------------------------------------------------------------
/documents/SoftwareArchitectureDesignDocument_v1.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rust-Proof/rustproof/654b0043d2e45129bff17a56adcbf3f689471477/documents/SoftwareArchitectureDesignDocument_v1.0.pdf
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Running Examples
2 | ```sh
3 | $ cargo run --example
4 | ```
5 | ```sh
6 | $ cargo run --example temp
7 | ```
8 |
--------------------------------------------------------------------------------
/scripts/travis-z3.sh:
--------------------------------------------------------------------------------
1 | # Copyright Takayuki Muranushi (c) 2015
2 |
3 | # All rights reserved.
4 |
5 | # Redistribution and use in source and binary forms, with or without
6 | # modification, are permitted provided that the following conditions are met:
7 |
8 | # * Redistributions of source code must retain the above copyright
9 | # notice, this list of conditions and the following disclaimer.
10 |
11 | # * Redistributions in binary form must reproduce the above
12 | # copyright notice, this list of conditions and the following
13 | # disclaimer in the documentation and/or other materials provided
14 | # with the distribution.
15 |
16 | # * Neither the name of Takayuki Muranushi nor the names of other
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 |
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 |
33 |
34 | #!/bin/bash
35 |
36 | mkdir -p ~/.local/bin
37 | mkdir -p ~/.local/lib
38 | wget https://github.com/Z3Prover/z3/releases/download/z3-4.4.1/z3-4.4.1-x64-ubuntu-14.04.zip
39 | unzip z3-4.4.1-x64-ubuntu-14.04.zip
40 | cp z3-4.4.1-x64-ubuntu-14.04/bin/z3 ~/.local/bin
41 | cp z3-4.4.1-x64-ubuntu-14.04/bin/*.so ~/.local/lib
42 |
--------------------------------------------------------------------------------
/src/expression/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Internal data structure and related functions to represent logical expressions.
12 |
13 | //#[macro_use]
14 | extern crate term;
15 | use std::fmt;
16 |
17 | // Boolean Expression type
18 | #[derive(Clone, PartialEq)]
19 | pub enum Expression {
20 | // Two sub-expressions joined by an operator
21 | BinaryExpression(BinaryExpressionData),
22 | // A sub-expression acted upon by an operator
23 | UnaryExpression(UnaryExpressionData),
24 | // A variable; should be either one of a function's formal arguments,
25 | // a special "return" variable, or something from an encapsulating scope.
26 | VariableMapping(VariableMappingData),
27 | // Boolean literals
28 | BooleanLiteral(bool),
29 | // Integer literals
30 | UnsignedBitVector(UnsignedBitVectorData),
31 | SignedBitVector(SignedBitVectorData)
32 | }
33 |
34 | // Used for representing Expression types as strings, recursively.
35 | impl fmt::Display for Expression {
36 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 | match *self {
38 | Expression::BinaryExpression (ref b) => {
39 | write!(f, "({} {} {})", *b.left, b.op, *b.right)
40 | },
41 | Expression::UnaryExpression (ref u) => write!(f, "({} {})", u.op, *u.e),
42 | Expression::VariableMapping (ref v) => write!(f, "({}: {})", v.name, v.var_type),
43 | Expression::BooleanLiteral (ref b) => write!(f, "({})", b),
44 | Expression::UnsignedBitVector(ref u) => {
45 | write!(f, "({}u{})", u.value, u.size.to_string())
46 | },
47 | Expression::SignedBitVector(ref s) => {
48 | write!(f, "({}i{})", s.value, s.size.to_string())
49 | }
50 | }
51 | }
52 | }
53 |
54 | impl fmt::Debug for Expression {
55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 | write!(f, "{}", self)
57 | }
58 | }
59 |
60 | #[derive(Clone, PartialEq)]
61 | pub struct BinaryExpressionData {
62 | pub op: BinaryOperator,
63 | pub left: Box,
64 | pub right: Box
65 | }
66 |
67 | #[derive(Clone, PartialEq)]
68 | pub struct UnaryExpressionData {
69 | pub op: UnaryOperator,
70 | pub e: Box
71 | }
72 |
73 | #[derive(Clone, Debug)]
74 | pub struct VariableMappingData { pub name: String, pub var_type: Types }
75 |
76 | // Check equality for VariableMappingData types.
77 | // Should return true if the name and type of the variables are the same.
78 | impl PartialEq for VariableMappingData {
79 | fn eq(&self, _rhs: &VariableMappingData) -> bool {
80 | return (self.name == _rhs.name) && (self.var_type == _rhs.var_type);
81 | }
82 | }
83 |
84 | // Ensures it is clear that VariableMappingData has full equality.
85 | impl Eq for VariableMappingData {}
86 |
87 | impl fmt::Display for VariableMappingData {
88 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 | write!(f, "({}: {})", self.name, self.var_type)
90 | }
91 | }
92 |
93 | #[derive(Clone, PartialEq)]
94 | pub struct UnsignedBitVectorData {
95 | pub size: u8,
96 | pub value: u64,
97 | }
98 |
99 | #[derive(Clone, PartialEq)]
100 | pub struct SignedBitVectorData {
101 | pub size: u8,
102 | pub value: i64,
103 | }
104 |
105 | #[derive(Clone, PartialEq)]
106 | pub enum BinaryOperator {
107 | // Normal operators
108 | Addition,
109 | Subtraction,
110 | Multiplication,
111 | Division,
112 | Modulo,
113 | // Overflow operators
114 | SignedMultiplicationDoesNotOverflow,
115 | SignedMultiplicationDoesNotUnderflow,
116 | UnsignedMultiplicationDoesNotOverflow,
117 | // Bitwise operators
118 | BitwiseOr,
119 | BitwiseAnd,
120 | BitwiseXor,
121 | BitwiseLeftShift,
122 | BitwiseRightShift,
123 | // Comparison operators
124 | LessThan,
125 | LessThanOrEqual,
126 | GreaterThan,
127 | GreaterThanOrEqual,
128 | Equal,
129 | NotEqual,
130 | // Boolean logical operators
131 | And,
132 | Or,
133 | Xor,
134 | Implication,
135 | BiImplication,
136 | }
137 |
138 | impl fmt::Display for BinaryOperator {
139 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 | match *self {
141 | BinaryOperator::Addition => write!(f, "+"),
142 | BinaryOperator::Subtraction => write!(f, "-"),
143 | BinaryOperator::Multiplication => write!(f, "*"),
144 | BinaryOperator::Division => write!(f, "/"),
145 | BinaryOperator::Modulo => write!(f, "%"),
146 | BinaryOperator::SignedMultiplicationDoesNotOverflow => {
147 | write!(f, "s_mul_no_overflow")
148 | },
149 | BinaryOperator::SignedMultiplicationDoesNotUnderflow => {
150 | write!(f, "s_mul_no_underflow")
151 | },
152 | BinaryOperator::UnsignedMultiplicationDoesNotOverflow => {
153 | write!(f, "u_mul_no_overflow")
154 | },
155 | BinaryOperator::BitwiseOr => write!(f, "|"),
156 | BinaryOperator::BitwiseAnd => write!(f, "&"),
157 | BinaryOperator::BitwiseXor => write!(f, "^"),
158 | BinaryOperator::BitwiseLeftShift => write!(f, "<<"),
159 | BinaryOperator::BitwiseRightShift => write!(f, ">>"),
160 | BinaryOperator::LessThan => write!(f, "<"),
161 | BinaryOperator::LessThanOrEqual => write!(f, "<="),
162 | BinaryOperator::GreaterThan => write!(f, ">"),
163 | BinaryOperator::GreaterThanOrEqual => write!(f, ">="),
164 | BinaryOperator::Equal => write!(f, "=="),
165 | BinaryOperator::NotEqual => write!(f, "!="),
166 | BinaryOperator::And => write!(f, "AND"),
167 | BinaryOperator::Or => write!(f, "OR"),
168 | BinaryOperator::Xor => write!(f, "XOR"),
169 | BinaryOperator::Implication => write!(f, "IMPLIES"),
170 | BinaryOperator::BiImplication => write!(f, "EQUIV"),
171 | }
172 | }
173 | }
174 |
175 | #[derive(Clone, PartialEq)]
176 | pub enum UnaryOperator {
177 | Negation,
178 | BitwiseNot,
179 | // Boolean logical operator
180 | Not,
181 | }
182 |
183 | impl fmt::Display for UnaryOperator {
184 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 | match *self {
186 | UnaryOperator::Negation => { write!(f, "-") },
187 | UnaryOperator::BitwiseNot => { write!(f, "!") },
188 | UnaryOperator::Not => { write!(f, "NOT") }
189 | }
190 | }
191 | }
192 |
193 | #[derive(Clone, PartialEq, Debug)]
194 | pub enum Types {
195 | Bool,
196 | I8,
197 | I16,
198 | I32,
199 | I64,
200 | U8,
201 | U16,
202 | U32,
203 | U64,
204 | Void
205 | }
206 |
207 | impl fmt::Display for Types {
208 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 | match *self {
210 | Types::Bool => { write!(f, "bool") },
211 | Types::I8 => { write!(f, "i8") },
212 | Types::I16 => { write!(f, "i16") },
213 | Types::I32 => { write!(f, "i32") },
214 | Types::I64 => { write!(f, "i64") },
215 | Types::U8 => { write!(f, "u8") },
216 | Types::U16 => { write!(f, "u16") },
217 | Types::U32 => { write!(f, "u32") },
218 | Types::U64 => { write!(f, "u64") },
219 | Types::Void => { write!(f, "()") },
220 | }
221 | }
222 | }
223 |
224 | /// Recurses through an Expression and replaces any instance of a variable with a given Expression.
225 | ///
226 | /// # Arguments:
227 | /// * `source_expression` - The Expression to be recursed through.
228 | /// * `target` - The variable to be replaced.
229 | /// * `replacement` - The Expression to replace the target, if found.
230 | ///
231 | /// # Remarks:
232 | ///
233 | pub fn substitute_variable_with_expression (source_expression: &mut Expression,
234 | target: &VariableMappingData,
235 | replacement: &Expression) {
236 | let mut replace: bool = false;
237 | match source_expression {
238 | &mut Expression::BinaryExpression(ref mut b) => {
239 | // Recurisvely call the sub-expressions
240 | substitute_variable_with_expression(&mut(*b.left), target, replacement);
241 | substitute_variable_with_expression(&mut(*b.right), target, replacement);
242 | },
243 | &mut Expression::UnaryExpression(ref mut u) => {
244 | // Recurisvely call the sub-expression
245 | substitute_variable_with_expression(&mut(*u.e), target, replacement);
246 | },
247 | &mut Expression::VariableMapping(ref mut v) => {
248 | // Substitute the variable if it matches the target
249 | if v == target {
250 | replace = true;
251 | }
252 | },
253 | _ => {
254 | // No substitution should be done
255 | }
256 | }
257 |
258 | // Substitute the variable after the match to avoid scope issues
259 | if replace {
260 | *source_expression = replacement.clone();
261 | }
262 | }
263 |
264 | /// Recurses through an Expression and returns the type it would evaluate to.
265 | ///
266 | /// # Arguments:
267 | /// * `expression` - An Expression whose evaluation type will be returned.
268 | ///
269 | /// # Return:
270 | /// * A String representation of the type that should return from the top level of the Expression.
271 | ///
272 | /// # Remarks:
273 | ///
274 | pub fn determine_evaluation_type ( expression: &Expression ) -> Types {
275 | match ty_check(expression) {
276 | Ok(_) => {
277 | match *expression {
278 | Expression::BinaryExpression(ref b) => {
279 | match b.op {
280 | BinaryOperator::Addition
281 | | BinaryOperator::Subtraction
282 | | BinaryOperator::Multiplication
283 | | BinaryOperator::Division
284 | | BinaryOperator::Modulo
285 | | BinaryOperator::BitwiseLeftShift
286 | | BinaryOperator::BitwiseRightShift
287 | | BinaryOperator::BitwiseOr
288 | | BinaryOperator::BitwiseAnd
289 | | BinaryOperator::BitwiseXor => determine_evaluation_type(&*b.left),
290 | BinaryOperator::LessThan
291 | | BinaryOperator::LessThanOrEqual
292 | | BinaryOperator::GreaterThan
293 | | BinaryOperator::GreaterThanOrEqual
294 | | BinaryOperator::SignedMultiplicationDoesNotOverflow
295 | | BinaryOperator::SignedMultiplicationDoesNotUnderflow
296 | | BinaryOperator::UnsignedMultiplicationDoesNotOverflow
297 | | BinaryOperator::Equal
298 | | BinaryOperator::NotEqual
299 | | BinaryOperator::And
300 | | BinaryOperator::Or
301 | | BinaryOperator::Xor
302 | | BinaryOperator::Implication
303 | | BinaryOperator::BiImplication => Types::Bool,
304 | }
305 | },
306 | Expression::UnaryExpression(ref u) => {
307 | match u.op {
308 | UnaryOperator::Negation
309 | | UnaryOperator::Not => determine_evaluation_type(&*u.e),
310 | UnaryOperator::BitwiseNot => determine_evaluation_type(&*u.e),
311 | }
312 | },
313 | Expression::VariableMapping(ref v) => v.var_type.clone(),
314 | Expression::BooleanLiteral(_) => Types::Bool,
315 | Expression::UnsignedBitVector(ref u) => {
316 | match u.size {
317 | 8 => Types::U8,
318 | 16 => Types::U16,
319 | 32 => Types::U32,
320 | 64 => Types::U64,
321 | _ => {
322 | rp_error!(
323 | "Invalid or Unsupported integer type: \"u{}\"",
324 | u.size.to_string()
325 | );
326 | }
327 | }
328 | },
329 | Expression::SignedBitVector(ref s) => {
330 | match s.size {
331 | 8 => Types::I8,
332 | 16 => Types::I16,
333 | 32 => Types::I32,
334 | 64 => Types::I64,
335 | _ => {
336 | rp_error!(
337 | "Invalid or Unsupported integer type: \"i{}\"",
338 | s.size.to_string()
339 | );
340 | }
341 | }
342 | }
343 | }
344 | },
345 | Err(e) => rp_error!("{}", e),
346 | }
347 | }
348 |
349 | /// Recurses through an Expression and checks for validity of types, operands, and integer bounds.
350 | ///
351 | /// # Arguments:
352 | /// * `expression` - An Expression whose type will be checked.
353 | ///
354 | /// # Return:
355 | /// * Ok(true) if all seems valid.
356 | /// * Err(String) otherwise, the String containing a message about the first problem encountered.
357 | ///
358 | /// # Remarks:
359 | ///
360 | pub fn ty_check( expression: &Expression ) -> Result {
361 | match *expression {
362 | Expression::BinaryExpression(ref b) => {
363 | match b.op {
364 | BinaryOperator::Addition
365 | | BinaryOperator::Subtraction
366 | | BinaryOperator::Multiplication
367 | | BinaryOperator::Division
368 | | BinaryOperator::Modulo
369 | | BinaryOperator::SignedMultiplicationDoesNotOverflow
370 | | BinaryOperator::SignedMultiplicationDoesNotUnderflow
371 | | BinaryOperator::UnsignedMultiplicationDoesNotOverflow => {
372 | match ty_check(&*b.left) {
373 | Ok(_) => {
374 | match ty_check(&*b.right) {
375 | Ok(_) => {
376 | let l_type: Types = determine_evaluation_type(&*b.left);
377 | let r_type: Types = determine_evaluation_type(&*b.right);
378 | // Ensure both operands are numeric types
379 | if (l_type == Types::Bool) || (r_type == Types::Bool) {
380 | Err(
381 | format!(
382 | "Invalid use of binary operator {} on boolean \
383 | value(s)",
384 | b.op
385 | )
386 | )
387 | // Ensure both operand types match
388 | } else if l_type != r_type {
389 | Err(
390 | format!(
391 | "Binary operand types do not match: {} {} {}",
392 | l_type,
393 | b.op,
394 | r_type
395 | )
396 | )
397 | } else {
398 | Ok(true)
399 | }
400 | },
401 | Err(e) => Err(e)
402 | }
403 | },
404 | Err(e) => Err(e)
405 | }
406 | },
407 | BinaryOperator::BitwiseLeftShift | BinaryOperator::BitwiseRightShift => {
408 | match ty_check(&*b.left) {
409 | Ok(_) => {
410 | match ty_check(&*b.right) {
411 | Ok(_) => {
412 | let l_type: Types = determine_evaluation_type(&*b.left);
413 | let r_type: Types = determine_evaluation_type(&*b.right);
414 | // Ensure both operands are numeric types
415 | if (l_type == Types::Bool) || (r_type == Types::Bool) {
416 | Err(
417 | format!(
418 | "Invalid use of binary operator {} on boolean \
419 | value(s)",
420 | b.op
421 | )
422 | )
423 | //Ensure both operand types are of same signedness
424 | } else if (is_valid_signed(&*b.left)
425 | && !is_valid_signed(&*b.right))
426 | || (is_valid_unsigned(&*b.left)
427 | && !is_valid_unsigned(&*b.right)) {
428 | Err(
429 | format!(
430 | "Binary operand types do not match: {} {} {}",
431 | l_type,
432 | b.op,
433 | r_type
434 | )
435 | )
436 | } else {
437 | Ok(true)
438 | }
439 | },
440 | Err(e) => Err(e)
441 | }
442 | },
443 | Err(e) => Err(e)
444 | }
445 | },
446 | BinaryOperator::BitwiseOr
447 | | BinaryOperator::BitwiseAnd
448 | | BinaryOperator::BitwiseXor => {
449 | match ty_check(&*b.left) {
450 | Ok(_) => {
451 | match ty_check(&*b.right) {
452 | Ok(_) => {
453 | let l_type: Types = determine_evaluation_type(&*b.left);
454 | let r_type: Types = determine_evaluation_type(&*b.right);
455 | // Ensure both operand types match
456 | if l_type != r_type {
457 | Err(
458 | format!(
459 | "Binary operand types do not match: {} {} {}",
460 | l_type,
461 | b.op,
462 | r_type
463 | )
464 | )
465 | } else {
466 | Ok(true)
467 | }
468 | },
469 | Err(e) => Err(e)
470 | }
471 | },
472 | Err(e) => Err(e)
473 | }
474 | },
475 | BinaryOperator::LessThan
476 | | BinaryOperator::LessThanOrEqual
477 | | BinaryOperator::GreaterThan
478 | | BinaryOperator::GreaterThanOrEqual => {
479 | match ty_check(&*b.left) {
480 | Ok(_) => {
481 | match ty_check(&*b.right) {
482 | Ok(_) => {
483 | let l_type: Types = determine_evaluation_type(&*b.left);
484 | let r_type: Types = determine_evaluation_type(&*b.right);
485 | // Ensure both operands are numeric types
486 | if (l_type == Types::Bool) || (r_type == Types::Bool) {
487 | Err(
488 | format!(
489 | "Invalid use of binary operator {} on boolean \
490 | value(s)",
491 | b.op
492 | )
493 | )
494 | // Ensure both operand types match
495 | } else if l_type != r_type {
496 | Err(
497 | format!(
498 | "Binary operand types do not match: {} {} {}",
499 | l_type,
500 | b.op,
501 | r_type
502 | )
503 | )
504 | } else {
505 | Ok(true)
506 | }
507 | },
508 | Err(e) => Err(e)
509 | }
510 | },
511 | Err(e) => Err(e)
512 | }
513 | },
514 | BinaryOperator::Equal | BinaryOperator::NotEqual => {
515 | match ty_check(&*b.left) {
516 | Ok(_) => {
517 | match ty_check(&*b.right) {
518 | Ok(_) => {
519 | let l_type: Types = determine_evaluation_type(&*b.left);
520 | let r_type: Types = determine_evaluation_type(&*b.right);
521 | // Ensure both operand types match
522 | if l_type != r_type {
523 | Err(
524 | format!(
525 | "Binary operand types do not match: {} {} {}",
526 | l_type,
527 | b.op,
528 | r_type
529 | )
530 | )
531 | } else {
532 | Ok(true)
533 | }
534 | },
535 | Err(e) => Err(e)
536 | }
537 | },
538 | Err(e) => Err(e)
539 | }
540 | },
541 | BinaryOperator::And | BinaryOperator::Or | BinaryOperator::Xor
542 | | BinaryOperator::Implication | BinaryOperator::BiImplication => {
543 | match ty_check(&*b.left) {
544 | Ok(_) => {
545 | match ty_check(&*b.right) {
546 | Ok(_) => {
547 | let l_type: Types = determine_evaluation_type(&*b.left);
548 | let r_type: Types = determine_evaluation_type(&*b.right);
549 | // Ensure both operands are boolean types
550 | if (l_type != Types::Bool) || (r_type != Types::Bool) {
551 | Err(
552 | format!(
553 | "Invalid use of binary operator {} on numeric value(s)",
554 | b.op
555 | )
556 | )
557 | // Ensure both operand types match
558 | } else if l_type != r_type {
559 | Err(
560 | format!(
561 | "Binary operand types do not match: {} {} {}",
562 | l_type,
563 | b.op,
564 | r_type
565 | )
566 | )
567 | } else {
568 | Ok(true)
569 | }
570 | },
571 | Err(e) => Err(e)
572 | }
573 | },
574 | Err(e) => Err(e)
575 | }
576 | }
577 | }
578 | },
579 | Expression::UnaryExpression(ref u) => {
580 | match u.op {
581 | UnaryOperator::Negation => {
582 | match ty_check(&*u.e) {
583 | Ok(_) => {
584 | let e_type: Types = determine_evaluation_type(&*u.e);
585 |
586 | // Ensure operand is a numeric type
587 | if e_type == Types::Bool {
588 | Err(
589 | format!(
590 | "Invalid use of operator {} on boolean value {}",
591 | u.op,
592 | *u.e
593 | )
594 | )
595 | // Ensure operand is not an unsigned type
596 | } else if is_valid_unsigned(&*u.e) {
597 | Err(
598 | format!(
599 | "Invalid use of operator {} on unsigned value {}",
600 | u.op,
601 | *u.e
602 | )
603 | )
604 | } else {
605 | Ok(true)
606 | }
607 | },
608 | Err(e) => Err(e)
609 | }
610 | },
611 | UnaryOperator::BitwiseNot => {
612 | match ty_check(&*u.e) {
613 | Ok(_) => Ok(true),
614 | Err(e) => Err(e)
615 | }
616 | },
617 | UnaryOperator::Not => {
618 | let e_type: Types = determine_evaluation_type(&*u.e);
619 | // Ensure operand is a boolean type
620 | if e_type != Types::Bool {
621 | Err(
622 | format!(
623 | "Invalid use of operator {} on non-boolean value {}",
624 | u.op,
625 | *u.e
626 | )
627 | )
628 | } else {
629 | Ok(true)
630 | }
631 | },
632 | }
633 | },
634 | Expression::VariableMapping(ref v) => {
635 | if let Types::Void = v.var_type {
636 | Err(format!("Variable {} has void type!", v.name))
637 | } else {
638 | Ok(true)
639 | }
640 | },
641 | Expression::BooleanLiteral(_) => {
642 | Ok(true)
643 | },
644 | Expression::UnsignedBitVector(ref u) => {
645 | match u.size {
646 | 8 => {
647 | if (u.value >= u8::min_value() as u64) && (u.value <= u8::max_value() as u64) {
648 | Ok(true)
649 | } else {
650 | Err(format!("Out of range value for u8 type: {}", u.value.to_string()))
651 | }
652 | },
653 | 16 => {
654 | if (u.value >= u16::min_value() as u64)
655 | && (u.value <= u16::max_value() as u64) {
656 | Ok(true)
657 | } else {
658 | Err(format!("Out of range value for u16 type: {}", u.value.to_string()))
659 | }
660 | },
661 | 32 => {
662 | if (u.value >= u32::min_value() as u64)
663 | && (u.value <= u32::max_value() as u64) {
664 | Ok(true)
665 | } else {
666 | Err(format!("Out of range value for u32 type: {}", u.value.to_string()))
667 | }
668 | },
669 | 64 => {
670 | if (u.value >= u64::min_value() as u64)
671 | && (u.value <= u64::max_value() as u64) {
672 | Ok(true)
673 | } else {
674 | Err(format!("Out of range value for u64 type: {}", u.value.to_string()))
675 | }
676 | },
677 | _ => {
678 | Err(format!("Invalid or unsupported integer type: \"u{}\"", u.size.to_string()))
679 | }
680 | }
681 | },
682 | Expression::SignedBitVector(ref s) => {
683 | match s.size {
684 | 8 => {
685 | if (s.value >= i8::min_value() as i64) && (s.value <= i8::max_value() as i64) {
686 | Ok(true)
687 | } else {
688 | Err(format!("Out of range value for i8 type: {}", s.value.to_string()))
689 | }
690 | },
691 | 16 => {
692 | if (s.value >= i16::min_value() as i64)
693 | && (s.value <= i16::max_value() as i64) {
694 | Ok(true)
695 | } else {
696 | Err(format!("Out of range value for i16 type: {}", s.value.to_string()))
697 | }
698 | },
699 | 32 => {
700 | if (s.value >= i32::min_value() as i64)
701 | && (s.value <= i32::max_value() as i64) {
702 | Ok(true)
703 | } else {
704 | Err(format!("Out of range value for i32 type: {}", s.value.to_string()))
705 | }
706 | },
707 | 64 => {
708 | if (s.value >= i64::min_value() as i64)
709 | && (s.value <= i64::max_value() as i64) {
710 | Ok(true)
711 | } else {
712 | Err(format!("Out of range value for i64 type: {}", s.value.to_string()))
713 | }
714 | },
715 | _ => {
716 | Err(
717 | format!(
718 | "Invalid or unsupported integer type: \"i{}\"",
719 | s.size.to_string()
720 | )
721 | )
722 | }
723 | }
724 | }
725 | }
726 | }
727 |
728 | /// Checks if an Expression matches one of the supported unsigned integer types
729 | ///
730 | /// # Arguments:
731 | /// * `e` - An Expression
732 | ///
733 | /// # Return:
734 | /// * `true` if it matches, `false` otherwise
735 | ///
736 | /// # Remarks:
737 | /// * Current supported types: u8, u16, u32, u64
738 | ///
739 | pub fn is_valid_unsigned(e: &Expression) -> bool {
740 | match *e {
741 | Expression::VariableMapping(ref v) => {
742 | is_unsigned_type(v.var_type.clone())
743 | }
744 | Expression::UnsignedBitVector(ref u) => {
745 | match u.size {
746 | 8u8 | 16u8 | 32u8 | 64u8 => true,
747 | _ => false,
748 | }
749 | }
750 | _ => false,
751 | }
752 | }
753 |
754 | /// Checks if an Expression matches one of the supported signed integer types
755 | ///
756 | /// # Arguments:
757 | /// * `e` - An Expression
758 | ///
759 | /// # Return:
760 | /// * `true` if it matches, `false` otherwise
761 | ///
762 | /// # Remarks:
763 | /// * Current supported types: i8, i16, i32, i64
764 | ///
765 | pub fn is_valid_signed(e: &Expression) -> bool {
766 | match *e {
767 | Expression::VariableMapping(ref v) => {
768 | is_signed_type(v.var_type.clone())
769 | }
770 | Expression::SignedBitVector(ref s) => {
771 | match s.size {
772 | 8u8 | 16u8 | 32u8 | 64u8 => true,
773 | _ => false,
774 | }
775 | }
776 | _ => false,
777 | }
778 | }
779 |
780 | /// Checks if a Types, like the return from determine_evaluation_type(), matches one of the
781 | /// supported unsigned integer types
782 | ///
783 | /// # Arguments:
784 | /// * `t` - A Types
785 | ///
786 | /// # Return:
787 | /// * `true` if it matches, `false` otherwise
788 | ///
789 | /// # Remarks:
790 | /// * Current supported types: u8, u16, u32, u64
791 | ///
792 | pub fn is_unsigned_type(t: Types) -> bool {
793 | match t {
794 | Types::U8 | Types::U16 | Types::U32 | Types::U64 => true,
795 | _ => false,
796 | }
797 | }
798 |
799 | /// Checks if a Types, like the return from determine_evaluation_type(), matches one of the
800 | /// supported signed integer types
801 | ///
802 | /// # Arguments:
803 | /// * `t` - A Types
804 | ///
805 | /// # Return:
806 | /// * `true` if it matches, `false` otherwise
807 | ///
808 | /// # Remarks:
809 | /// * Current supported types: i8, i16, i32, i64
810 | ///
811 | pub fn is_signed_type(t: Types) -> bool {
812 | match t {
813 | Types::I8 | Types::I16 | Types::I32 | Types::I64 => true,
814 | _ => false,
815 | }
816 | }
817 |
818 | /// Returns a `Types` interpreted from a `String` representing a variable or literal type
819 | ///
820 | /// # Arguments:
821 | /// * `s` - A String
822 | ///
823 | /// # Return:
824 | /// * A Types
825 | ///
826 | /// # Remarks:
827 | /// * Current supported types: bool, i8, i16, i32, i64, u8, u16, u32, u64
828 | pub fn string_to_type(s: String) -> Types {
829 | match s.as_str() {
830 | "bool" => Types::Bool,
831 | "i8" => Types::I8,
832 | "i16" => Types::I16,
833 | "i32" => Types::I32,
834 | "i64" => Types::I64,
835 | "u8" => Types::U8,
836 | "u16" => Types::U16,
837 | "u32" => Types::U32,
838 | "u64" => Types::U64,
839 | "()" => Types::Void,
840 | _ => unimplemented!(),
841 | }
842 | }
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Rustproof is a compiler plugin for the Rust programming language. It generates verification
12 | //! conditions for functions with supplied preconditions(`P`) and postconditions(`Q`). That is, given a
13 | //! supplied postcondition on a function, rustproof uses [predicate transformer semantics](https://en.wikipedia.org/wiki/Predicate_transformer_semantics)
14 | //! to generate a weakest precondition(`WP`). The verification condition `P->WP` is then checked for
15 | //! satisfiability by a SMT solver ([z3](https://github.com/Z3Prover/z3)).
16 | //! This process results in a proof of function correctness.
17 | //!
18 |
19 | //! Access the rustproof README [here](https://github.com/Rust-Proof/rustproof/blob/master/README.md).
20 | //!
21 | //! The following documentation is intended for the devlopers of rustproof.
22 | //! These descibed modules are not user-facing.
23 |
24 |
25 | #![crate_type="dylib"]
26 | #![feature(plugin_registrar, rustc_private)]
27 |
28 | #[macro_use] extern crate syntax;
29 | #[macro_use] mod reporting;
30 |
31 | // External crate imports
32 | #[macro_use] extern crate rustproof_libsmt;
33 | // The following line is being weird to me sometimes
34 | #[macro_use] extern crate log;
35 | extern crate petgraph;
36 | extern crate rustc;
37 | extern crate rustc_plugin;
38 | extern crate rustc_data_structures;
39 | extern crate rustc_const_math;
40 | //extern crate syntax;
41 | extern crate rustc_errors;
42 |
43 | // External imports
44 | use rustc_data_structures::indexed_vec::Idx;
45 | use rustc_plugin::Registry;
46 | use rustc::mir::repr::{Mir, BasicBlock, BasicBlockData, Arg, Temp, Var, ArgDecl, TempDecl, VarDecl};
47 | use rustc::mir::transform::{Pass, MirPass, MirSource};
48 | use rustc::ty::{TyCtxt, FnOutput};
49 | use syntax::feature_gate::AttributeType;
50 | use syntax::parse::token::InternedString;
51 | use syntax::ast::MetaItemKind;
52 |
53 | // Local imports
54 | use expression::*;
55 | use parser::*;
56 | use smt_output::*;
57 | use weakest_precondition::*;
58 |
59 | // rustproof modules
60 | mod expression;
61 | mod parser;
62 | mod smt_output;
63 | mod weakest_precondition;
64 | #[cfg(test)]
65 | mod tests;
66 |
67 |
68 | // Register plugin with compiler
69 | #[plugin_registrar]
70 | pub fn registrar(reg: &mut Registry) {
71 | // If debug is an argument, set the debug flag to true
72 | let mut debug = false;
73 | for arg in reg.args() {
74 | if arg.clone().unwrap().node == MetaItemKind::Word(InternedString::new("debug")) {
75 | debug = true;
76 | }
77 | else {
78 | rp_error!("unrecognized plugin argument");
79 | }
80 | }
81 |
82 | let visitor = MirVisitor { debug: debug };
83 |
84 | reg.register_attribute("condition".to_string(), AttributeType::Whitelisted);
85 | reg.register_mir_pass(Box::new(visitor));
86 | }
87 |
88 | /// Represents the data from the MIR pass relevant to the function being analyzed
89 | ///
90 |
91 | /// # Purpose:
92 | /// * Used to pass data from the MIR and the computed weakest_precondition
93 |
94 | ///
95 | pub struct MirData<'tcx> {
96 | block_data: Vec<&'tcx BasicBlockData<'tcx>>,
97 | arg_data: Vec<&'tcx ArgDecl<'tcx>>,
98 | var_data: Vec<&'tcx VarDecl<'tcx>>,
99 | temp_data: Vec<&'tcx TempDecl<'tcx>>,
100 | func_return_type: Types,
101 | }
102 |
103 | // required struct for Pass impl
104 | struct MirVisitor { debug: bool }
105 |
106 | /// This must exist and must be blank
107 | impl <'tcx> Pass for MirVisitor {}
108 |
109 | /// Sets up the compiler to go through MIR code.
110 | ///
111 | /// # Remarks:
112 | impl <'tcx> MirPass<'tcx> for MirVisitor {
113 | // Visit the MIR of the entire program
114 | fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
115 | let debug = self.debug;
116 | // Clear the stored attributes in the builder
117 | let mut pre_string = "".to_string();
118 | let mut post_string = "".to_string();
119 | let pre_expr;
120 | let post_expr;
121 |
122 | // Store relevant data
123 | let item_id = src.item_id();
124 | let def_id = tcx.map.local_def_id(item_id);
125 | let name = tcx.item_path_str(def_id);
126 | let attrs = tcx.map.attrs(item_id);
127 |
128 | // TODO: Find a better way to do this
129 | for attr in attrs {
130 | parse_attribute(&mut pre_string, &mut post_string, attr);
131 | }
132 |
133 | // TODO: Find a better condition check
134 | if pre_string != "" {
135 | // Parse the pre- and postcondition arguments
136 | pre_expr = Some(parser::parse_condition(pre_string.as_str()));
137 | post_expr = Some(parser::parse_condition(post_string.as_str()));
138 |
139 | // Get the return type
140 | let func_return_type: String = match mir.return_ty {
141 | FnOutput::FnConverging(t) => {
142 | t.to_string()
143 | },
144 | _ => unimplemented!(),
145 | };
146 |
147 | // Struct to carry MIR data to later stages
148 | let mut data = MirData {
149 | block_data: Vec::new(),
150 | arg_data: Vec::new(),
151 | var_data: Vec::new(),
152 | temp_data: Vec::new(),
153 | func_return_type: string_to_type(func_return_type),
154 | };
155 |
156 | // Get the basic block data
157 | for index in 0..mir.basic_blocks().len() {
158 | let block = BasicBlock::new(index);
159 | data.block_data.push(&mir[block]);
160 | }
161 |
162 | // Get the function argument declarations
163 | for index in 0..mir.arg_decls.len() {
164 | let arg = Arg::new(index);
165 | data.arg_data.push(&mir.arg_decls[arg]);
166 | }
167 |
168 | // Get the temp declarations
169 | for index in 0..mir.temp_decls.len() {
170 | let temp = Temp::new(index);
171 | data.temp_data.push(&mir.temp_decls[temp]);
172 | }
173 |
174 | // Get the variable declarations
175 | for index in 0..mir.var_decls.len() {
176 | let var = Var::new(index);
177 | data.var_data.push(&mir.var_decls[var]);
178 | }
179 |
180 | if debug {
181 | println!("Printing basic blocks...");
182 | for index in 0..data.block_data.len() {
183 | println!("bb{:?}\n{:#?}\n", index, data.block_data[index]);
184 | }
185 | }
186 |
187 | // Generate the weakest precondition
188 | let weakest_precondition = gen(0, &mut data, &post_expr, debug);
189 |
190 | // Create the verification condition, P -> WP
191 | let verification_condition: Expression = Expression::BinaryExpression( BinaryExpressionData{
192 | op: BinaryOperator::Implication,
193 | left: Box::new(pre_expr.as_ref().unwrap().clone()),
194 | right: Box::new(weakest_precondition.as_ref().unwrap().clone())
195 | } );
196 |
197 | // FIXME: Debug should not be a const; it must be user-facing
198 | if debug {
199 | println!("vc: {}\n", verification_condition);
200 | }
201 | // Check that the verification condition is correctly typed
202 | match expression::ty_check(&verification_condition) {
203 | Ok(_) => {},
204 | Err(e) => rp_error!("{}", e),
205 | }
206 |
207 | // Output to SMT-LIB format
208 | gen_smtlib(&verification_condition, name, debug);
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/parser/expression_parser.lalrpop:
--------------------------------------------------------------------------------
1 | use std::str::FromStr;
2 | use expression::*;
3 | grammar;
4 |
5 | pub E1: Expression = {
6 | => Expression::BinaryExpression( BinaryExpressionData {
7 | op: op, left: Box::new(left), right: Box::new(right)
8 | } ),
9 | E2,
10 | };
11 |
12 | E2: Expression = {
13 | => Expression::BinaryExpression( BinaryExpressionData {
14 | op: op, left: Box::new(left), right: Box::new(right)
15 | } ),
16 | E3,
17 | };
18 |
19 | E3: Expression = {
20 | => Expression::BinaryExpression( BinaryExpressionData {
21 | op: op, left: Box::new(left), right: Box::new(right)
22 | } ),
23 | E4,
24 | };
25 |
26 | E4: Expression = {
27 | => Expression::BinaryExpression( BinaryExpressionData {
28 | op: op, left: Box::new(left), right: Box::new(right)
29 | } ),
30 | E5,
31 | };
32 |
33 | E5: Expression = {
34 | => Expression::BinaryExpression( BinaryExpressionData {
35 | op: op, left: Box::new(left), right: Box::new(right)
36 | } ),
37 | E6,
38 | };
39 |
40 | E6: Expression = {
41 | => Expression::BinaryExpression( BinaryExpressionData {
42 | op: op, left: Box::new(left), right: Box::new(right)
43 | } ),
44 | E7,
45 | };
46 |
47 | E7: Expression = {
48 | => Expression::BinaryExpression( BinaryExpressionData {
49 | op: op, left: Box::new(left), right: Box::new(right)
50 | } ),
51 | E8,
52 | };
53 |
54 | E8: Expression = {
55 | => Expression::BinaryExpression( BinaryExpressionData {
56 | op: op, left: Box::new(left), right: Box::new(right)
57 | } ),
58 | E9,
59 | };
60 |
61 | E9: Expression = {
62 | => Expression::UnaryExpression( UnaryExpressionData {
63 | op: op, e: Box::new(e)
64 | } ),
65 | E10,
66 | };
67 |
68 | E10: Expression = {
69 | "true" => Expression::BooleanLiteral(true),
70 | "false" => Expression::BooleanLiteral(false),
71 | "i8" => Expression::SignedBitVector( SignedBitVectorData {
72 | size: 8, value: i8::from_str(i).unwrap() as i64
73 | } ),
74 | "i16" => Expression::SignedBitVector( SignedBitVectorData {
75 | size: 16, value: i16::from_str(i).unwrap() as i64
76 | } ),
77 | "i32" => Expression::SignedBitVector( SignedBitVectorData {
78 | size: 32, value: i32::from_str(i).unwrap() as i64
79 | } ),
80 | "i64" => Expression::SignedBitVector( SignedBitVectorData {
81 | size: 64, value: i64::from_str(i).unwrap() as i64
82 | } ),
83 | "i8" => Expression::SignedBitVector( SignedBitVectorData {
84 | size: 8, value: i8::from_str(i).unwrap() as i64
85 | } ),
86 | "i16" => Expression::SignedBitVector( SignedBitVectorData {
87 | size: 16, value: i16::from_str(i).unwrap() as i64
88 | } ),
89 | "i32" => Expression::SignedBitVector( SignedBitVectorData {
90 | size: 32, value: i32::from_str(i).unwrap() as i64
91 | } ),
92 | "i64" => Expression::SignedBitVector( SignedBitVectorData {
93 | size: 64, value: i64::from_str(i).unwrap() as i64
94 | } ),
95 | "u8" => Expression::UnsignedBitVector( UnsignedBitVectorData {
96 | size: 8, value: u8::from_str(i).unwrap() as u64
97 | } ),
98 | "u16" => Expression::UnsignedBitVector( UnsignedBitVectorData {
99 | size: 16, value: u16::from_str(i).unwrap() as u64
100 | } ),
101 | "u32" => Expression::UnsignedBitVector( UnsignedBitVectorData {
102 | size: 32, value: u32::from_str(i).unwrap() as u64
103 | } ),
104 | "u64" => Expression::UnsignedBitVector( UnsignedBitVectorData {
105 | size: 64, value: u64::from_str(i).unwrap() as u64
106 | } ),
107 | ":" => Expression::VariableMapping( VariableMappingData {
108 | name: n, var_type: t
109 | } ),
110 | => ib,
111 | "(" ")" => e,
112 | };
113 |
114 | UOP: UnaryOperator = {
115 | "-" => UnaryOperator::Negation,
116 | "!" => UnaryOperator::BitwiseNot,
117 | "NOT" => UnaryOperator::Not,
118 | };
119 |
120 | BOP1: BinaryOperator = {
121 | "&&" => BinaryOperator::And,
122 | "AND" => BinaryOperator::And,
123 | "||" => BinaryOperator::Or,
124 | "OR" => BinaryOperator::Or,
125 | "XOR" => BinaryOperator::Xor,
126 | "=>" => BinaryOperator::Implication,
127 | "IMPLIES" => BinaryOperator::Implication,
128 | "<=>" => BinaryOperator::BiImplication,
129 | "EQUIV" => BinaryOperator::BiImplication,
130 | };
131 |
132 | BOP2: BinaryOperator = {
133 | "<" => BinaryOperator::LessThan,
134 | "<=" => BinaryOperator::LessThanOrEqual,
135 | ">" => BinaryOperator::GreaterThan,
136 | ">=" => BinaryOperator::GreaterThanOrEqual,
137 | "==" => BinaryOperator::Equal,
138 | "!=" => BinaryOperator::NotEqual,
139 | };
140 |
141 | BOP3: BinaryOperator = {
142 | "|" => BinaryOperator::BitwiseOr,
143 | };
144 |
145 | BOP4: BinaryOperator = {
146 | "^" => BinaryOperator::BitwiseXor,
147 | };
148 |
149 | BOP5: BinaryOperator = {
150 | "&" => BinaryOperator::BitwiseAnd,
151 | };
152 |
153 | BOP6: BinaryOperator = {
154 | "<<" => BinaryOperator::BitwiseLeftShift,
155 | ">>" => BinaryOperator::BitwiseRightShift,
156 | };
157 |
158 | BOP7: BinaryOperator = {
159 | "+" => BinaryOperator::Addition,
160 | "-" => BinaryOperator::Subtraction,
161 | };
162 |
163 | BOP8: BinaryOperator = {
164 | "*" => BinaryOperator::Multiplication,
165 | "/" => BinaryOperator::Division,
166 | "%" => BinaryOperator::Modulo,
167 | };
168 |
169 | IDENTIFIER: String = {
170 | => i.to_string(),
171 | => {
172 | match i {
173 | "as" | "box" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern" |
174 | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod" |
175 | "move" | "mut" | "pub" | "ref" | "self" | "Self" | "static" | "struct" |
176 | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while" |
177 | "abstract" | "alignof" | "become" | "do" | "final" | "macro" | "offsetof" |
178 | "override" | "priv" | "proc" | "pure" | "sizeof" | "typeof" | "unsized" | "virtual" |
179 | "yield" => {
180 | panic!("Use of reserved keyword as identifier: {}", i.to_string());
181 | },
182 | _ => i.to_string(),
183 | }
184 | },
185 | };
186 |
187 | TYPE: Types = {
188 | "bool" => Types::Bool,
189 | "i8" => Types::I8,
190 | "i16" => Types::I16,
191 | "i32" => Types::I32,
192 | "i64" => Types::I64,
193 | "u8" => Types::U8,
194 | "u16" => Types::U16,
195 | "u32" => Types::U32,
196 | "u64" => Types::U64,
197 | };
198 |
199 | INT_BOUNDS: Expression = {
200 | "i8::MAX" => Expression::SignedBitVector( SignedBitVectorData {
201 | size: 8, value: i8::max_value() as i64
202 | } ),
203 | "i16::MAX" => Expression::SignedBitVector( SignedBitVectorData {
204 | size: 16, value: i16::max_value() as i64
205 | } ),
206 | "i32::MAX" => Expression::SignedBitVector( SignedBitVectorData {
207 | size: 32, value: i32::max_value() as i64
208 | } ),
209 | "i64::MAX" => Expression::SignedBitVector( SignedBitVectorData {
210 | size: 64, value: i64::max_value() as i64
211 | } ),
212 | "i8::MIN" => Expression::SignedBitVector( SignedBitVectorData {
213 | size: 8, value: i8::min_value() as i64
214 | } ),
215 | "i16::MIN" => Expression::SignedBitVector( SignedBitVectorData {
216 | size: 16, value: i16::min_value() as i64
217 | } ),
218 | "i32::MIN" => Expression::SignedBitVector( SignedBitVectorData {
219 | size: 32, value: i32::min_value() as i64
220 | } ),
221 | "i64::MIN" => Expression::SignedBitVector( SignedBitVectorData {
222 | size: 64, value: i64::min_value() as i64
223 | } ),
224 | "u8::MAX" => Expression::UnsignedBitVector( UnsignedBitVectorData {
225 | size: 8, value: u8::max_value() as u64
226 | } ),
227 | "u16::MAX" => Expression::UnsignedBitVector( UnsignedBitVectorData {
228 | size: 16, value: u16::max_value() as u64
229 | } ),
230 | "u32::MAX" => Expression::UnsignedBitVector( UnsignedBitVectorData {
231 | size: 32, value: u32::max_value() as u64
232 | } ),
233 | "u64::MAX" => Expression::UnsignedBitVector( UnsignedBitVectorData {
234 | size: 64, value: u64::max_value() as u64
235 | } ),
236 | "u8::MIN" => Expression::UnsignedBitVector( UnsignedBitVectorData {
237 | size: 8, value: u8::min_value() as u64
238 | } ),
239 | "u16::MIN" => Expression::UnsignedBitVector( UnsignedBitVectorData {
240 | size: 16, value: u16::min_value() as u64
241 | } ),
242 | "u32::MIN" => Expression::UnsignedBitVector( UnsignedBitVectorData {
243 | size: 32, value: u32::min_value() as u64
244 | } ),
245 | "u64::MIN" => Expression::UnsignedBitVector( UnsignedBitVectorData {
246 | size: 64, value: u64::min_value() as u64
247 | } ),
248 | };
249 |
--------------------------------------------------------------------------------
/src/parser/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Parses rustproof attribute definitions.
12 |
13 | extern crate syntax;
14 |
15 | mod expression_parser;
16 |
17 | use syntax::ast::{MetaItemKind, Attribute_};
18 | use syntax::codemap::Spanned;
19 | use expression::{Expression, ty_check};
20 |
21 | /// Analyzes an attribute on a function in the compiled code, and if the attribute is "condition",
22 | /// ensures correct usage. If usage is correct, it stores the argument strings.
23 | ///
24 | /// # Arguments:
25 | /// * `pre_string` - Empty string. Will contain a user-submitted precondition if found.
26 | /// * `post_string` - Empty string. Will contain a user-submitted postcondition if found.
27 | /// * `attr` - The attribute being analyzed.
28 | ///
29 | /// # Remarks:
30 | /// * Currently supported `ConstInt`: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `bool`
31 | ///
32 | pub fn parse_attribute(pre_string: &mut String,
33 | post_string: &mut String,
34 | attr: &Spanned) {
35 | if let MetaItemKind::List(ref attribute_name, ref args) = attr.node.value.node {
36 | // Ignore if not a condition attribute
37 | if attribute_name == "condition" {
38 | // Only accept if exactly 2 arguments
39 | if args.len() != 2 {
40 | rp_error!("Condition attribute must have exactly 2 arguments.");
41 | }
42 | // Parse the first argument
43 | if let MetaItemKind::NameValue(ref i_string, ref literal) = args[0].node {
44 | if i_string != "pre" {
45 | rp_error!( "The first argument must be named \"pre\". {} was provided.",
46 | i_string);
47 | }
48 | // Get the argument
49 | if let syntax::ast::LitKind::Str(ref i_string, _) = literal.node {
50 | *pre_string = i_string.to_string();
51 | } else {
52 | rp_error!("Conditions must be strings. \
53 | Try wrapping conditions in quotation marks.");
54 | }
55 | } else {
56 | rp_error!("The first argument must be named \"pre\".");
57 | }
58 | // Parse the second argument
59 | if let MetaItemKind::NameValue(ref i_string, ref literal) = args[1].node {
60 | if i_string != "post" {
61 | rp_error!( "The second argument must be named \"post\". {} was provided.",
62 | i_string);
63 | }
64 | // Get the argument
65 | if let syntax::ast::LitKind::Str(ref i_string, _) = literal.node {
66 | *post_string = i_string.to_string();
67 | } else {
68 | rp_error!("Conditions must be strings. \
69 | Try wrapping conditions in quotation marks.");
70 | }
71 | } else {
72 | rp_error!("The second argument must be named \"post\".");
73 | }
74 | } // Ignore if not a condition attribute
75 | }
76 | }
77 |
78 | /// Calls the expression parser on a given precondition or postcondition.
79 | ///
80 | /// # Arguments:
81 | /// * `condition` - A user-submitted string
82 | ///
83 | /// # Return:
84 | /// * If `condition` is valid, an Expression representing it.
85 | ///
86 | /// # Remarks:
87 | /// * Current supported types: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `bool`
88 | pub fn parse_condition(condition: &str) -> Expression {
89 | match expression_parser::parse_E1(condition) {
90 | Ok(e) => {
91 | match ty_check(&e) {
92 | Ok(_) => return e,
93 | Err(s) => rp_error!("{}", s),
94 | }
95 | },
96 | Err(e) => rp_error!("Error parsing condition \"{}\": {:?}", condition, e)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/reporting/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Prints user-facing errors and warnings.
12 |
13 | // Warning macro
14 | macro_rules! rp_warn {
15 | ($fmt:expr) => ({
16 | use rustc_errors::{ColorConfig, Handler};
17 | use syntax::codemap::CodeMap;
18 | use std::rc::Rc;
19 | let codemap = Rc::new(CodeMap::new());
20 | let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
21 | let str = format!(concat!($fmt, "\n"));
22 | handler.warn(&str);
23 | });
24 | ($fmt:expr, $($arg:tt)*) => ({
25 | use rustc_errors::{ColorConfig, Handler};
26 | use syntax::codemap::CodeMap;
27 | use std::rc::Rc;
28 | let codemap = Rc::new(CodeMap::new());
29 | let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
30 | let str = format!(concat!($fmt, "\n"), $($arg)*);
31 | handler.warn(&str);
32 | });
33 | }
34 |
35 | // Error macro
36 | macro_rules! rp_error {
37 | ($fmt:expr) => ({
38 | use rustc_errors::{ColorConfig, Handler};
39 | use syntax::codemap::CodeMap;
40 | use std::rc::Rc;
41 | use std::process;
42 | let codemap = Rc::new(CodeMap::new());
43 | let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
44 | let str = concat!($fmt, "\n");
45 | handler.err(&str);
46 | process::exit(1);
47 | });
48 | ($fmt:expr, $($arg:tt)*) => ({
49 | use rustc_errors::{ColorConfig, Handler};
50 | use syntax::codemap::CodeMap;
51 | use std::rc::Rc;
52 | use std::process;
53 | let codemap = Rc::new(CodeMap::new());
54 | let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
55 | let str = format!(concat!($fmt, "\n"), $($arg)*);
56 | handler.err(&str);
57 | process::exit(1);
58 | });
59 | }
60 |
--------------------------------------------------------------------------------
/src/smt_output/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Interface between rustproof and libsmt(z3).
12 |
13 | use std::fmt::Debug;
14 |
15 | use rustproof_libsmt::backends::smtlib2::*;
16 | use rustproof_libsmt::backends::backend::*;
17 | use rustproof_libsmt::backends::z3;
18 | use rustproof_libsmt::theories::{bitvec, core};
19 | use rustproof_libsmt::logics::qf_abv::*;
20 | use petgraph::graph::NodeIndex;
21 |
22 | use expression::*;
23 |
24 | /// Invokes Z3 to check the satisfiability of a verification condition.
25 | ///
26 | /// # Arguments:
27 | /// * `vc` - A verification condition as an Expression.
28 | /// * `name` - The name of the function whose verification condition is being checked.
29 | /// * `debug` - A flag to enable/disable debug printing.
30 | ///
31 | /// # Remarks:
32 | /// * Simply satisfying P->WP isn't enough; that will only tell us if P->WP is _sometimes true_. We
33 | /// * need to verify that !(P->WP) is *unsatisfiable* to determine that P->WP is _always true_.
34 | ///
35 | pub fn gen_smtlib (vc: &Expression, name: String, debug: bool) {
36 | // Define an instance of Z3
37 | let mut z3: z3::Z3 = Default::default();
38 |
39 | // Declare a logic to use
40 | let mut solver = SMTLib2::new(Some(QF_ABV));
41 |
42 | // Check the satisfiability of the solver
43 | let vcon = solver.expr2smtlib(vc);
44 | let _ = solver.assert(core::OpCodes::Not, &[vcon]);
45 |
46 | let (_, check) = solver.solve(&mut z3, debug);
47 | match check {
48 | SMTRes::Sat(_, ref model) => {
49 | println!(
50 | "\nfn {}(..)\tVerification Condition is not valid.\n\n{}\n",
51 | name,
52 | model.clone().unwrap()
53 | );
54 | },
55 | SMTRes::Unsat(..) => {
56 | println!("\nfn {}(..)\tVerification Condition is valid.\n", name);
57 | },
58 | SMTRes::Error(ref error, _) => {
59 | println!("\nfn {}(..)\tError in Verification Condition Generation.\n{}\n", name, error);
60 | }
61 | }
62 |
63 | }
64 |
65 | pub trait Pred2SMT {
66 | type Idx: Debug + Clone;
67 | type Logic: Logic;
68 |
69 | fn expr2smtlib (&mut self, &Expression) -> Self::Idx;
70 | }
71 |
72 | impl Pred2SMT for SMTLib2 {
73 | type Idx = NodeIndex;
74 | type Logic = QF_ABV;
75 |
76 | fn expr2smtlib (&mut self, vc: &Expression) -> Self::Idx {
77 | match *vc {
78 | Expression::BinaryExpression (ref b) => {
79 | let l = self.expr2smtlib(b.left.as_ref());
80 | let r = self.expr2smtlib(b.right.as_ref());
81 | match b.op {
82 | BinaryOperator::Addition => {
83 | return self.assert(bitvec::OpCodes::BvAdd, &[l,r]);
84 | },
85 | BinaryOperator::Subtraction => {
86 | return self.assert(bitvec::OpCodes::BvSub, &[l,r]);
87 | },
88 | BinaryOperator::Multiplication => {
89 | return self.assert(bitvec::OpCodes::BvMul, &[l,r]);
90 | },
91 | BinaryOperator::Division => {
92 | // Check for signedness
93 | if is_signed_type(determine_evaluation_type(vc)) {
94 | return self.assert(bitvec::OpCodes::BvSDiv, &[l,r]);
95 | } else {
96 | return self.assert(bitvec::OpCodes::BvUDiv, &[l,r]);
97 | }
98 | },
99 | BinaryOperator::Modulo => {
100 | // Check for signedness
101 | if is_signed_type(determine_evaluation_type(vc)) {
102 | return self.assert(bitvec::OpCodes::BvSMod, &[l,r]);
103 | } else {
104 | return self.assert(bitvec::OpCodes::BvURem, &[l,r]);
105 | }
106 | },
107 | BinaryOperator::SignedMultiplicationDoesNotOverflow => {
108 | return self.assert(bitvec::OpCodes::BvSMulDoesNotOverflow, &[l,r]);
109 | },
110 | BinaryOperator::SignedMultiplicationDoesNotUnderflow => {
111 | return self.assert(bitvec::OpCodes::BvSMulDoesNotUnderflow, &[l,r]);
112 | },
113 | BinaryOperator::UnsignedMultiplicationDoesNotOverflow => {
114 | return self.assert(bitvec::OpCodes::BvUMulDoesNotOverflow, &[l,r]);
115 | },
116 | BinaryOperator::BitwiseOr => {
117 | if determine_evaluation_type(vc) == Types::Bool {
118 | return self.assert(core::OpCodes::Or, &[l,r]);
119 | } else {
120 | return self.assert(bitvec::OpCodes::BvOr, &[l,r]);
121 | }
122 | },
123 | BinaryOperator::BitwiseAnd => {
124 | if determine_evaluation_type(vc) == Types::Bool {
125 | return self.assert(core::OpCodes::And, &[l,r]);
126 | } else {
127 | return self.assert(bitvec::OpCodes::BvAnd, &[l,r]);
128 | }
129 | },
130 | BinaryOperator::BitwiseXor => {
131 | if determine_evaluation_type(vc) == Types::Bool {
132 | return self.assert(core::OpCodes::Xor, &[l,r]);
133 | } else {
134 | return self.assert(bitvec::OpCodes::BvXor, &[l,r]);
135 | }
136 | },
137 | BinaryOperator::BitwiseLeftShift => {
138 | return self.assert(bitvec::OpCodes::BvShl, &[l,r]);
139 | },
140 | BinaryOperator::BitwiseRightShift => {
141 | // Check for signedness
142 | if is_signed_type(determine_evaluation_type(vc)) {
143 | return self.assert(bitvec::OpCodes::BvAShr, &[l,r]);
144 | } else {
145 | return self.assert(bitvec::OpCodes::BvLShr, &[l,r]);
146 | }
147 | },
148 | BinaryOperator::LessThan => {
149 | if is_signed_type(determine_evaluation_type(b.left.as_ref())) {
150 | return self.assert(bitvec::OpCodes::BvSLt, &[l,r]);
151 | } else {
152 | return self.assert(bitvec::OpCodes::BvULt, &[l,r]);
153 | }
154 | },
155 | BinaryOperator::LessThanOrEqual => {
156 | // Check for signedness
157 | if is_signed_type(determine_evaluation_type(b.left.as_ref())) {
158 | return self.assert(bitvec::OpCodes::BvSLe, &[l,r]);
159 | } else {
160 | return self.assert(bitvec::OpCodes::BvULe, &[l,r]);
161 | }
162 | },
163 | BinaryOperator::GreaterThan => {
164 | // Check for signedness
165 | if is_signed_type(determine_evaluation_type(b.left.as_ref())) {
166 | return self.assert(bitvec::OpCodes::BvSGt, &[l,r]);
167 | } else {
168 | return self.assert(bitvec::OpCodes::BvUGt, &[l,r]);
169 | }
170 | },
171 | BinaryOperator::GreaterThanOrEqual => {
172 | // Check for signedness
173 | if is_signed_type(determine_evaluation_type(b.left.as_ref())) {
174 | return self.assert(bitvec::OpCodes::BvSGe, &[l,r]);
175 | } else {
176 | return self.assert(bitvec::OpCodes::BvUGe, &[l,r]);
177 | }
178 | },
179 | BinaryOperator::Equal
180 | | BinaryOperator::BiImplication => {
181 | return self.assert(core::OpCodes::Cmp, &[l,r]);
182 | }
183 | BinaryOperator::NotEqual => {
184 | let eq = self.assert(core::OpCodes::Cmp, &[l,r]);
185 | return self.assert(core::OpCodes::Not, &[eq]);
186 | },
187 | BinaryOperator::And => {
188 | return self.assert(core::OpCodes::And, &[l,r]);
189 | },
190 | BinaryOperator::Or => {
191 | return self.assert(core::OpCodes::Or, &[l,r]);
192 | },
193 | BinaryOperator::Xor => {
194 | return self.assert(core::OpCodes::Xor, &[l,r]);
195 | },
196 | BinaryOperator::Implication => {
197 | return self.assert(core::OpCodes::Imply, &[l,r]);
198 | },
199 | }
200 | },
201 | Expression::UnaryExpression (ref u) => {
202 | let n = self.expr2smtlib(u.e.as_ref());
203 | match u.op {
204 | UnaryOperator::Negation => {
205 | return self.assert(bitvec::OpCodes::BvNeg, &[n]);
206 | },
207 | UnaryOperator::BitwiseNot => {
208 | return self.assert(bitvec::OpCodes::BvNot, &[n]);
209 | },
210 | UnaryOperator::Not => {
211 | return self.assert(core::OpCodes::Not, &[n]);
212 | },
213 | }
214 | },
215 | Expression::VariableMapping (ref v) => {
216 | let sort = match v.var_type {
217 | Types::Bool => bitvec::Sorts::Bool,
218 | Types::I8 | Types::U8 => bitvec::Sorts::BitVector(8),
219 | Types::I16 | Types::U16 => bitvec::Sorts::BitVector(16),
220 | Types::I32 | Types::U32 => bitvec::Sorts::BitVector(32),
221 | Types::I64 | Types::U64 => bitvec::Sorts::BitVector(64),
222 | Types::Void => unreachable!(),
223 | };
224 | return self.new_var(Some(&v.name), sort);
225 | },
226 | Expression::BooleanLiteral (ref b) => {
227 | return self.new_const(core::OpCodes::Const(*b));
228 | },
229 | Expression::UnsignedBitVector (ref u) => {
230 | return bv_const!(self, u.value, u.size as usize);
231 | },
232 | Expression::SignedBitVector (ref s) => {
233 | return bv_const!(self, s.value as u64, s.size as usize);
234 | }
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/tests/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | mod test_reporting;
12 | mod test_expression;
13 | mod system_tests;
14 |
--------------------------------------------------------------------------------
/src/tests/system_tests.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | use std::process::Command;
12 |
13 | // Uses a /example file as a system test for rustproof
14 | // returns false on verification condition mismatch from function name prefix
15 | fn test_example_file(file: &str) -> bool {
16 |
17 | // Clean rustproof to ensure this test runs
18 | // Note: this does not increase test time
19 | Command::new("cargo").args(&["clean","-p", "rustproof"]).output()
20 | .expect("failed to execute child process: cargo clean -p rustproof");
21 |
22 | // Compile the example
23 | let output = Command::new("cargo").args(&["build", "--test", file]).output()
24 | .expect(format!("failed to execute child process: cargo build --test {}", file).as_str());
25 |
26 | // Read strerr for any rustproof errors. if found, return false
27 | let stderr_result = String::from_utf8_lossy(&output.stderr);
28 | let split_err = stderr_result.split("\n");
29 | for s in split_err {
30 | if s.starts_with("error") {
31 | return false;
32 | }
33 | }
34 |
35 | // Process the output
36 | let stdout_result = String::from_utf8_lossy(&output.stdout);
37 | let split = stdout_result.split("\n");
38 |
39 | // For each function
40 | for s in split{
41 | if s.starts_with("fn") {
42 | // If the output line starts with "invalid" it must end with "not valid"
43 | // If the output line starts with "valid" it must end with "valid"
44 | // If there is a mismatch, we have a test failure.
45 | // Lines beginning with anything else should be ignored
46 | if !((s.starts_with("fn invalid") && s.ends_with("not valid."))
47 | || (s.starts_with("fn valid") && s.ends_with("valid.") && !s.ends_with("not valid."))) {
48 | return false;
49 | }
50 | }
51 | }
52 |
53 | return true;
54 | }
55 |
56 | // Original test condition example test
57 | #[test]
58 | fn test_examples() {
59 | assert!(test_example_file("test_conditions"));
60 | }
61 |
62 | // Test examples for unsigned examples
63 | #[test]
64 | fn test_unsigned_examples(){
65 | assert!(test_example_file("test_unsigned"));
66 | }
67 |
68 | // Test examples for signed examples
69 | #[test]
70 | fn test_signed_examples(){
71 | assert!(test_example_file("test_signed"));
72 | }
73 |
74 | // Test example for boolean examples
75 | #[test]
76 | fn test_boolean_examples(){
77 | assert!(test_example_file("test_boolean_arithmetic"));
78 | }
79 |
80 | // Test example for conditional examples
81 | #[test]
82 | fn test_conditional_examples(){
83 | assert!(test_example_file("test_conditionals"));
84 | }
85 |
86 | // Test example for assertion examples
87 | #[test]
88 | fn test_assertion_examples(){
89 | assert!(test_example_file("test_assert"));
90 | }
91 |
92 | // Tests whether the system testing functions are appropriately catching test failure
93 | #[test]
94 | #[should_panic]
95 | fn test_system_test_validity() {
96 | assert!(test_example_file("test_fail_valid"));
97 | assert!(test_example_file("test_fail_invalid"));
98 | }
99 |
--------------------------------------------------------------------------------
/src/tests/test_expression.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | use expression::*;
12 |
13 | #[test]
14 | fn test_all_substitute_binary_operators() {
15 | substitute_variable_with_expression_less_than();
16 | substitute_variable_with_expression_less_than_or_equal();
17 | substitute_variable_with_expression_greater_than();
18 | substitute_variable_with_expression_greater_than_or_equal();
19 | }
20 |
21 | #[test]
22 | fn test_check_signedness() {
23 | check_signedness_bool();
24 | check_signedness_i8();
25 | check_signedness_i16();
26 | check_signedness_i32();
27 | check_signedness_i64();
28 | check_signedness_u8();
29 | check_signedness_u16();
30 | check_signedness_u32();
31 | check_signedness_u64();
32 | }
33 |
34 | #[test]
35 | fn determine_evaluation_type_comparison_unary(){
36 | let u: Expression = Expression::VariableMapping( VariableMappingData{
37 | name: "x".to_string(),
38 | var_type: Types::Bool
39 | });
40 | let to_test: Expression = Expression::UnaryExpression( UnaryExpressionData{
41 | op: UnaryOperator::Not,
42 | e: Box::new(u.clone()),
43 | });
44 | let determined_type = determine_evaluation_type(&to_test);
45 | let correct_result = Types::Bool;
46 | assert_eq!(determined_type, correct_result);
47 | }
48 |
49 | #[test]
50 | fn determine_evaluation_type_comparison_binary(){
51 | let left_side: Expression = Expression::VariableMapping( VariableMappingData{
52 | name:"x".to_string(),
53 | var_type: Types::I32
54 | });
55 | let right_side: Expression = Expression::VariableMapping( VariableMappingData{
56 | name:"y".to_string(),
57 | var_type: Types::I32
58 | });
59 | let to_test: Expression = Expression::BinaryExpression(BinaryExpressionData{
60 | op: BinaryOperator::Addition,
61 | left: Box::new(left_side.clone()),
62 | right: Box::new(right_side.clone()),
63 | });
64 |
65 | let returned_string = determine_evaluation_type(&to_test);
66 | let correct_result = Types::I32;
67 | assert_eq!(returned_string, correct_result);
68 | }
69 |
70 | #[test]
71 | fn substitute_unary_operator_not(){
72 | let target_var : VariableMappingData = VariableMappingData {
73 | name: "x".to_string(),
74 | var_type: Types::I32
75 | };
76 | let target: Expression = Expression::VariableMapping(target_var.clone());
77 | let replacement: Expression = Expression::VariableMapping( VariableMappingData{
78 | name: "y".to_string(),
79 | var_type: Types::I32
80 | });
81 | let mut p: Expression = Expression::UnaryExpression(UnaryExpressionData{
82 | op: UnaryOperator::Not,
83 | e: Box::new(target.clone()),
84 | });
85 |
86 | let correct_result: Expression = Expression::UnaryExpression(UnaryExpressionData{
87 | op: UnaryOperator::Not,
88 | e: Box::new(replacement.clone() ),
89 | });
90 | substitute_variable_with_expression(&mut p, &target_var, &replacement);
91 | assert_eq!(p, correct_result);
92 | }
93 |
94 | fn substitute_variable_with_expression_greater_than_or_equal(){
95 | let target_var : VariableMappingData = VariableMappingData {
96 | name: "x".to_string(),
97 | var_type: Types::I32
98 | };
99 | let target: Expression = Expression::VariableMapping( target_var.clone() );
100 | let superfluous: Expression = Expression::VariableMapping( VariableMappingData {
101 | name: "z".to_string(),
102 | var_type: Types::I32
103 | });
104 | let replacement: Expression = Expression::VariableMapping( VariableMappingData {
105 | name: "y".to_string(),
106 | var_type: Types::I32
107 | });
108 | let mut p: Expression = Expression::BinaryExpression( BinaryExpressionData{
109 | op: BinaryOperator::GreaterThanOrEqual,
110 | left: Box::new( target.clone() ),
111 | right: Box::new( superfluous.clone() ),
112 | });
113 |
114 | let correct_result: Expression = Expression::BinaryExpression( BinaryExpressionData{
115 | op: BinaryOperator::GreaterThanOrEqual,
116 | left: Box::new( replacement.clone() ),
117 | right: Box::new( superfluous.clone() ),
118 | });
119 | substitute_variable_with_expression(&mut p, &target_var, &replacement);
120 | assert_eq!(p, correct_result);
121 | }
122 |
123 | fn substitute_variable_with_expression_less_than() {
124 | let target_var : VariableMappingData = VariableMappingData {
125 | name: "x".to_string(),
126 | var_type: Types::I32
127 | };
128 | let target: Expression = Expression::VariableMapping( target_var.clone() );
129 | let superfluous: Expression = Expression::VariableMapping( VariableMappingData {
130 | name: "z".to_string(),
131 | var_type: Types::I32
132 | });
133 | let replacement: Expression = Expression::VariableMapping( VariableMappingData {
134 | name: "y".to_string(),
135 | var_type: Types::I32
136 | });
137 | let mut p: Expression = Expression::BinaryExpression( BinaryExpressionData{
138 | op: BinaryOperator::LessThan,
139 | left: Box::new( target.clone() ),
140 | right: Box::new( superfluous.clone() ),
141 | });
142 |
143 | let correct_result: Expression = Expression::BinaryExpression( BinaryExpressionData{
144 | op: BinaryOperator::LessThan,
145 | left: Box::new( replacement.clone() ),
146 | right: Box::new( superfluous.clone() ),
147 | });
148 | substitute_variable_with_expression(&mut p, &target_var, &replacement);
149 | assert_eq!(p, correct_result);
150 | }
151 |
152 | fn substitute_variable_with_expression_less_than_or_equal() {
153 | let target_var : VariableMappingData = VariableMappingData {
154 | name: "x".to_string(),
155 | var_type: Types::I32
156 | };
157 | let target: Expression = Expression::VariableMapping( target_var.clone() );
158 | let superfluous: Expression = Expression::VariableMapping( VariableMappingData {
159 | name: "z".to_string(),
160 | var_type: Types::I32
161 | });
162 | let replacement: Expression = Expression::VariableMapping( VariableMappingData {
163 | name: "y".to_string(),
164 | var_type: Types::I32
165 | });
166 | let mut p: Expression = Expression::BinaryExpression( BinaryExpressionData{
167 | op: BinaryOperator::LessThanOrEqual,
168 | left: Box::new( target.clone() ),
169 | right: Box::new( superfluous.clone() ),
170 | });
171 |
172 | let correct_result: Expression = Expression::BinaryExpression( BinaryExpressionData{
173 | op: BinaryOperator::LessThanOrEqual,
174 | left: Box::new( replacement.clone() ),
175 | right: Box::new( superfluous.clone() ),
176 | });
177 | substitute_variable_with_expression(&mut p, &target_var, &replacement);
178 | assert_eq!(p, correct_result);
179 | }
180 |
181 | fn substitute_variable_with_expression_greater_than(){
182 | let target_var : VariableMappingData = VariableMappingData {
183 | name: "x".to_string(),
184 | var_type: Types::I32
185 | };
186 | let target: Expression = Expression::VariableMapping( target_var.clone() );
187 | let superfluous: Expression = Expression::VariableMapping( VariableMappingData {
188 | name: "z".to_string(),
189 | var_type: Types::I32
190 | });
191 | let replacement: Expression = Expression::VariableMapping( VariableMappingData {
192 | name: "y".to_string(),
193 | var_type: Types::I32
194 | });
195 | let mut p: Expression = Expression::BinaryExpression( BinaryExpressionData{
196 | op: BinaryOperator::GreaterThan,
197 | left: Box::new( target.clone() ),
198 | right: Box::new( superfluous.clone() ),
199 | });
200 |
201 | let correct_result: Expression = Expression::BinaryExpression( BinaryExpressionData{
202 | op: BinaryOperator::GreaterThan,
203 | left: Box::new( replacement.clone() ),
204 | right: Box::new( superfluous.clone() ),
205 | });
206 | substitute_variable_with_expression(&mut p, &target_var, &replacement);
207 | assert_eq!(p, correct_result);
208 |
209 | }
210 |
211 | #[test]
212 | fn variable_mapping_data_equality() {
213 | let var1: VariableMappingData = VariableMappingData {
214 | name: "x".to_string(),
215 | var_type: Types::I32
216 | };
217 | let var2: VariableMappingData = VariableMappingData {
218 | name: "x".to_string(),
219 | var_type: Types::I32
220 | };
221 | let var3: VariableMappingData = VariableMappingData {
222 | name: "y".to_string(),
223 | var_type: Types::I32
224 | };
225 | let var4: VariableMappingData = VariableMappingData {
226 | name: "x".to_string(),
227 | var_type: Types::U32
228 | };
229 | let var5: VariableMappingData = VariableMappingData {
230 | name: "y".to_string(),
231 | var_type: Types::U32
232 | };
233 |
234 | assert!(var1 == var1);
235 | assert!(var1 == var2);
236 | assert!(var1 != var3);
237 | assert!(var1 != var4);
238 | assert!(var1 != var5);
239 | }
240 |
241 | fn check_signedness_bool() {
242 | let var: Expression = Expression::VariableMapping(VariableMappingData {
243 | name: "v".to_string(),
244 | var_type: Types::Bool,
245 | });
246 | let boolean: Expression = Expression::BooleanLiteral(true);
247 |
248 | assert!(!is_valid_signed(&var));
249 | assert!(!is_valid_unsigned(&var));
250 | assert!(!is_valid_signed(&boolean));
251 | assert!(!is_valid_unsigned(&boolean));
252 | }
253 |
254 | fn check_signedness_i8() {
255 | let var: Expression = Expression::VariableMapping(VariableMappingData {
256 | name: "v".to_string(),
257 | var_type: Types::I8,
258 | });
259 | let num: Expression = Expression::SignedBitVector(SignedBitVectorData {
260 | size: 8u8,
261 | value: 1i64,
262 | });
263 |
264 | assert!(is_valid_signed(&var));
265 | assert!(is_valid_signed(&num));
266 | assert!(!is_valid_unsigned(&var));
267 | assert!(!is_valid_unsigned(&num));
268 | }
269 |
270 | fn check_signedness_i16() {
271 | let var: Expression = Expression::VariableMapping(VariableMappingData {
272 | name: "v".to_string(),
273 | var_type: Types::I16,
274 | });
275 | let num: Expression = Expression::SignedBitVector(SignedBitVectorData {
276 | size: 16u8,
277 | value: 1i64,
278 | });
279 |
280 | assert!(is_valid_signed(&var));
281 | assert!(is_valid_signed(&num));
282 | assert!(!is_valid_unsigned(&var));
283 | assert!(!is_valid_unsigned(&num));
284 | }
285 |
286 | fn check_signedness_i32() {
287 | let var: Expression = Expression::VariableMapping(VariableMappingData {
288 | name: "v".to_string(),
289 | var_type: Types::I32,
290 | });
291 | let num: Expression = Expression::SignedBitVector(SignedBitVectorData {
292 | size: 32u8,
293 | value: 1i64,
294 | });
295 |
296 | assert!(is_valid_signed(&var));
297 | assert!(is_valid_signed(&num));
298 | assert!(!is_valid_unsigned(&var));
299 | assert!(!is_valid_unsigned(&num));
300 | }
301 |
302 | fn check_signedness_i64() {
303 | let var: Expression = Expression::VariableMapping(VariableMappingData {
304 | name: "v".to_string(),
305 | var_type: Types::I64,
306 | });
307 | let num: Expression = Expression::SignedBitVector(SignedBitVectorData {
308 | size: 64u8,
309 | value: 1i64,
310 | });
311 |
312 | assert!(is_valid_signed(&var));
313 | assert!(is_valid_signed(&num));
314 | assert!(!is_valid_unsigned(&var));
315 | assert!(!is_valid_unsigned(&num));
316 | }
317 |
318 | fn check_signedness_u8() {
319 | let var: Expression = Expression::VariableMapping(VariableMappingData {
320 | name: "v".to_string(),
321 | var_type: Types::U8,
322 | });
323 | let num: Expression = Expression::UnsignedBitVector(UnsignedBitVectorData {
324 | size: 8u8,
325 | value: 1u64,
326 | });
327 |
328 | assert!(!is_valid_signed(&var));
329 | assert!(!is_valid_signed(&num));
330 | assert!(is_valid_unsigned(&var));
331 | assert!(is_valid_unsigned(&num));
332 | }
333 |
334 | fn check_signedness_u16() {
335 | let var: Expression = Expression::VariableMapping(VariableMappingData {
336 | name: "v".to_string(),
337 | var_type: Types::U16,
338 | });
339 | let num: Expression = Expression::UnsignedBitVector(UnsignedBitVectorData {
340 | size: 16u8,
341 | value: 1u64,
342 | });
343 |
344 | assert!(!is_valid_signed(&var));
345 | assert!(!is_valid_signed(&num));
346 | assert!(is_valid_unsigned(&var));
347 | assert!(is_valid_unsigned(&num));
348 | }
349 |
350 | fn check_signedness_u32() {
351 | let var: Expression = Expression::VariableMapping(VariableMappingData {
352 | name: "v".to_string(),
353 | var_type: Types::U32,
354 | });
355 | let num: Expression = Expression::UnsignedBitVector(UnsignedBitVectorData {
356 | size: 32u8,
357 | value: 1u64,
358 | });
359 |
360 | assert!(!is_valid_signed(&var));
361 | assert!(!is_valid_signed(&num));
362 | assert!(is_valid_unsigned(&var));
363 | assert!(is_valid_unsigned(&num));
364 | }
365 |
366 | fn check_signedness_u64() {
367 | let var: Expression = Expression::VariableMapping(VariableMappingData {
368 | name: "v".to_string(),
369 | var_type: Types::U64,
370 | });
371 | let num: Expression = Expression::UnsignedBitVector(UnsignedBitVectorData {
372 | size: 64u8,
373 | value: 1u64,
374 | });
375 |
376 | assert!(!is_valid_signed(&var));
377 | assert!(!is_valid_signed(&num));
378 | assert!(is_valid_unsigned(&var));
379 | assert!(is_valid_unsigned(&num));
380 | }
--------------------------------------------------------------------------------
/src/tests/test_reporting.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 |
--------------------------------------------------------------------------------
/src/weakest_precondition/mod.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Generates a weakest precondition from MIR basic block data.
12 |
13 | extern crate rustc_const_math;
14 |
15 | use super::MirData;
16 | use expression::*;
17 | use rustc::mir::repr::*;
18 | use rustc::middle::const_val::ConstVal;
19 | use rustc_const_math::ConstInt;
20 | use rustc_data_structures::indexed_vec::Idx;
21 | use rustc::ty::{TypeVariants};
22 |
23 | mod overflow;
24 |
25 | /// Computes the weakest precondition for a given postcondition and a series of statements over one or more MIR basic blocks.
26 | ///
27 | /// # Arguments:
28 | /// * `index` - The index of the `BasicBlock` within MIR.
29 | /// * `data` - Contains the `BasicBlockData` and all argument, temp, and variable declarations from the MIR pass.
30 | /// * `post_expr` - The current weakest precondition (originally the postcondition) as an Expression.
31 | ///
32 | /// # Return Value:
33 | /// * Returns the weakest precondition generated from the `BasicBlock` in the form of an Expression.
34 | ///
35 | /// # Remarks:
36 | /// * This is the main generator for the weakest precondition, which evaluates the `BasicBlock`s recursively.
37 | ///
38 | pub fn gen(index: usize, data: &mut MirData, post_expr: &Option, debug: bool) -> Option {
39 | let mut wp: Option;
40 |
41 | // Parse basic block terminator data
42 | let terminator = data.block_data[index].terminator.clone().unwrap().kind;
43 | match terminator {
44 | // Assert{cond, expected, msg, target, cleanup}
45 | TerminatorKind::Assert{target, ..}
46 | | TerminatorKind::Goto{target} => {
47 | // Retrieve the weakest precondition from the following block
48 | wp = gen(target.index(), data, post_expr, debug);
49 | },
50 | TerminatorKind::Return => {
51 | // Return the post condition to the preceeding block
52 | return post_expr.clone();
53 | },
54 | // Call{func, args, destination, cleanup}
55 | TerminatorKind::Call{func, ..} => {
56 | // Determine if this is the end of a panic. (assumed false branch of assertion, so
57 | // return a precondition of false [this path will never be taken])
58 | match func {
59 | Operand::Constant (ref c) => {
60 | let s = format!("{:?}", c.literal);
61 | if s.contains("begin_panic") {
62 | return Some(Expression::BooleanLiteral(false));
63 | }
64 | },
65 | // Consume (ref l)
66 | Operand::Consume (..) => unimplemented!(),
67 | };
68 | // Due to the limited nature in which we handle Calls, we should never do anything
69 | // other than return early or hit the unimplemented!() panic above.
70 | unreachable!();
71 | },
72 | // Conditional statements
73 | // wp(if c x else y) => (c -> x) AND ((NOT c) -> y)
74 | TerminatorKind::If{cond, targets} => {
75 | // Generate weakest precondition for if and else clause
76 | let wp_if = gen(targets.0.index(), data, post_expr, debug);
77 | let wp_else = gen(targets.1.index(), data, post_expr, debug);
78 |
79 | // Generate the conditional expression
80 | let condition = match cond {
81 | Operand::Constant (ref constant) => {
82 | match constant.literal {
83 | Literal::Value {ref value} => {
84 | match *value {
85 | ConstVal::Bool (ref boolean) => {
86 | Expression::BooleanLiteral(*boolean)
87 | },
88 | _ => unreachable!(),
89 | }
90 | },
91 | _ => unimplemented!(),
92 | }
93 | },
94 | Operand::Consume(c) => { Expression::VariableMapping(gen_lvalue(c, data)) },
95 | };
96 | // Negate the conditional expression
97 | let not_condition = Expression::UnaryExpression(UnaryExpressionData {
98 | op: UnaryOperator::Not,
99 | e: Box::new(condition.clone())
100 | });
101 | // wp(If c x else y) => (c -> x) AND ((NOT c) -> y)
102 | wp = Some(Expression::BinaryExpression(BinaryExpressionData {
103 | op: BinaryOperator::And,
104 | left: Box::new(Expression::BinaryExpression(BinaryExpressionData {
105 | op: BinaryOperator::Implication,
106 | left: Box::new(condition.clone()),
107 | right: Box::new(wp_if.unwrap())
108 | })),
109 | right: Box::new(Expression::BinaryExpression(BinaryExpressionData {
110 | op: BinaryOperator::Implication,
111 | left: Box::new(not_condition.clone()),
112 | right: Box::new(wp_else.unwrap())
113 | }))
114 | }));
115 | },
116 | // Unimplemented TerminatorKinds
117 | // DropAndReplace{location, value, target, unwind}
118 | TerminatorKind::DropAndReplace{..} => unimplemented!(),
119 | // Drop{location, target, unwind}
120 | TerminatorKind::Drop{..} => unimplemented!(),
121 | TerminatorKind::Unreachable => unimplemented!(),
122 | TerminatorKind::Resume => unimplemented!(),
123 | // Switch{discr, adt_def, targets}
124 | TerminatorKind::Switch{..} => unimplemented!(),
125 | // SwitchInt{discr, switch_ty, values, targets}
126 | TerminatorKind::SwitchInt{..} => unimplemented!(),
127 | }
128 |
129 | // Examine the statements in reverse order
130 | let mut stmts = data.block_data[index].statements.clone();
131 | stmts.reverse();
132 |
133 | // Prints the current BasicBlock index
134 | if debug {
135 | println!("Processing bb{:?}:", index);
136 | }
137 |
138 | for stmt in stmts {
139 | // Modify the weakest precondition based on the statement
140 | wp = gen_stmt(wp.unwrap(), stmt, data, debug);
141 | }
142 |
143 | // Prints the result to be returned to the proceeding block
144 | if debug {
145 | println!("wp returned as\t{:?}\n", wp.clone().unwrap());
146 | }
147 |
148 | // Return the weakest precondition to the preceeding block, or to control
149 | wp
150 | }
151 |
152 | /// Returns a (possibly) modified weakest precondition based on the content of a statement
153 | ///
154 | /// # Arguments:
155 | /// * `wp` - The current weakest precondition
156 | /// * `stmt` - The statement to be processed.
157 | /// * `data` - Contains the `BasicBlockData` and all argument, temp, and variable declarations from
158 | /// the MIR pass.
159 | ///
160 | /// # Return Value:
161 | /// * Returns the modified weakest precondition with underflow check
162 | ///
163 | /// # Remarks:
164 | ///
165 | fn gen_stmt(mut wp: Expression, stmt: Statement, data: &mut MirData, debug: bool)
166 | -> Option {
167 | // Prints the current statement being processed.
168 | if debug {
169 | println!("processing statement\t{:?}\ninto expression\t\t{:?}", stmt, wp);
170 | }
171 |
172 | let lvalue: Option;
173 | let rvalue: Option;
174 |
175 | // Store the values of the statement
176 | match stmt.kind {
177 | StatementKind::Assign(ref lval, ref rval) => {
178 | lvalue = Some(lval.clone());
179 | rvalue = Some(rval.clone());
180 | },
181 | //_ => return Some(wp)
182 | }
183 | // The variable or temp on the left-hand side of the assignment
184 | let mut var = gen_lvalue(lvalue.unwrap(), data);
185 |
186 | // The expression on the right-hand side of the assignment
187 | let mut expression = Vec::new();
188 | match rvalue.clone().unwrap() {
189 | Rvalue::CheckedBinaryOp(ref binop, ref loperand, ref roperand) => {
190 | let lvalue: Expression = gen_expression(loperand, data);
191 | let rvalue: Expression = gen_expression(roperand, data);
192 | let op: BinaryOperator = match *binop {
193 | BinOp::Add => {
194 | // Add the overflow expression checks
195 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
196 | BinaryOperator::Addition
197 | },
198 | BinOp::Sub => {
199 | // Add the overflow and underflow expression checks
200 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
201 | BinaryOperator::Subtraction
202 | },
203 | BinOp::Mul => {
204 | // Add the overflow and underflow expression checks
205 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
206 | BinaryOperator::Multiplication
207 | },
208 | BinOp::Div => {
209 | // Add the overflow and underflow expression checks, if operands are signed
210 | if is_signed_type(determine_evaluation_type(&rvalue)) {
211 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
212 | }
213 | // Add the division by 0 expression check
214 | wp = add_zero_check(&wp, &rvalue);
215 | BinaryOperator::Division
216 | },
217 | BinOp::Rem => {
218 | // Add the overflow and underflow expression checks, if operands are signed
219 | if is_signed_type(determine_evaluation_type(&rvalue)) {
220 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
221 | }
222 | // Add the division by 0 expression check
223 | wp = add_zero_check(&wp, &rvalue);
224 | BinaryOperator::Modulo
225 | },
226 | BinOp::Shl => BinaryOperator::BitwiseLeftShift,
227 | BinOp::Shr => BinaryOperator::BitwiseRightShift,
228 | _ => rp_error!("Unsupported checked binary operation!"),
229 | };
230 |
231 | var.name = var.name + ".0";
232 |
233 | // Add the new BinaryExpressionData to the expression vector
234 | expression.push(Expression::BinaryExpression( BinaryExpressionData {
235 | op: op,
236 | left: Box::new(lvalue),
237 | right: Box::new(rvalue)
238 | } ));
239 | },
240 |
241 | Rvalue::BinaryOp(ref binop, ref lval, ref rval) => {
242 | let lvalue: Expression = gen_expression(lval, data);
243 | let rvalue: Expression = gen_expression(rval, data);
244 | let op: BinaryOperator = match *binop {
245 | BinOp::Add => {
246 | // Add the overflow expression check
247 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
248 | BinaryOperator::Addition
249 | },
250 | BinOp::Sub => {
251 | // Add the overflow and underflow expression checks
252 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
253 | BinaryOperator::Subtraction
254 | },
255 | BinOp::Mul => {
256 | // Add the overflow and underflow expression checks
257 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
258 | BinaryOperator::Multiplication
259 | },
260 | BinOp::Div => {
261 | // Add the overflow and underflow expression checks, if operands are signed
262 | if is_signed_type(determine_evaluation_type(&rvalue)) {
263 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
264 | }
265 | // Add the division by 0 expression check
266 | wp = add_zero_check(&wp, &rvalue);
267 | BinaryOperator::Division
268 | },
269 | BinOp::Rem => {
270 | // Add the overflow and underflow expression checks, if operands are signed
271 | if is_signed_type(determine_evaluation_type(&rvalue)) {
272 | wp = overflow::overflow_check(&wp, &var, binop, &lvalue, &rvalue);
273 | }
274 | // Add the division by 0 expression check
275 | wp = add_zero_check(&wp, &rvalue);
276 | BinaryOperator::Modulo
277 | },
278 | BinOp::BitOr => BinaryOperator::BitwiseOr,
279 | BinOp::BitAnd => BinaryOperator::BitwiseAnd,
280 | BinOp::BitXor => BinaryOperator::BitwiseXor,
281 | BinOp::Shl => BinaryOperator::BitwiseLeftShift,
282 | BinOp::Shr => BinaryOperator::BitwiseRightShift,
283 | BinOp::Lt => BinaryOperator::LessThan,
284 | BinOp::Le => BinaryOperator::LessThanOrEqual,
285 | BinOp::Gt => BinaryOperator::GreaterThan,
286 | BinOp::Ge => BinaryOperator::GreaterThanOrEqual,
287 | BinOp::Eq => BinaryOperator::Equal,
288 | BinOp::Ne => BinaryOperator::NotEqual,
289 | };
290 | // Add the expression to the vector
291 | expression.push(Expression::BinaryExpression( BinaryExpressionData {
292 | op: op,
293 | left: Box::new(lvalue),
294 | right: Box::new(rvalue)
295 | } ));
296 | },
297 | // Generates Rvalue to a UnaryOp
298 | Rvalue::UnaryOp(ref unop, ref val) => {
299 | let exp: Expression = gen_expression(val, data);
300 | let op: UnaryOperator = match *unop {
301 | UnOp::Not => {
302 | if determine_evaluation_type(&exp) == Types::Bool {
303 | UnaryOperator::Not
304 | } else {
305 | UnaryOperator::BitwiseNot
306 | }
307 | },
308 | UnOp::Neg => UnaryOperator::Negation,
309 | };
310 | // push the ne new exp onto the expression: Vec<>
311 | expression.push(Expression::UnaryExpression( UnaryExpressionData {
312 | op: op,
313 | e: Box::new(exp)
314 | } ));
315 | },
316 | // FIXME: need def
317 | Rvalue::Use(ref operand) => {
318 | expression.push(gen_expression(operand, data));
319 | },
320 | // FIXME: need def
321 | Rvalue::Aggregate(ref ag_kind, ref vec_operand) => {
322 | match *ag_kind {
323 | AggregateKind::Tuple => {
324 | for operand in vec_operand.iter() {
325 | let e = Expression::VariableMapping( VariableMappingData {
326 | //name: var.name.as_str().to_string() + "." + i.to_string().as_str(),
327 | name: format!("{:?}", operand),
328 | var_type: gen_ty(operand, data)
329 | } );
330 | expression.push(e);
331 | }
332 | },
333 | _ => rp_error!("Unsupported aggregate: only tuples are supported"),
334 | }
335 | },
336 | // FIXME: need def
337 | // Cast(ref cast_kind, ref cast_operand, ref cast_ty)
338 | Rvalue::Cast(..) => {
339 | expression.push(Expression::VariableMapping(var.clone()));
340 | },
341 | // FIXME: need def
342 | // Ref(ref ref_region, ref ref_borrow_kind, ref ref_lvalue) => {
343 | Rvalue::Ref(..) => {
344 | expression.push(Expression::VariableMapping(var.clone()));
345 | },
346 | // Unimplemented Rvalues
347 | Rvalue::Box(..) => unimplemented!(),
348 | Rvalue::Len(..) => unimplemented!(),
349 | _ => unimplemented!(),
350 | };
351 |
352 | // Replace any appearance of var in the weakest precondition with the expression
353 | for expr in &expression {
354 | substitute_variable_with_expression( &mut wp, &var, expr );
355 | }
356 | // Prints the new weakest precondition
357 | if debug {
358 | println!("new expression\t\t{:?}\n--------------------------------", wp.clone());
359 | }
360 | return Some(wp);
361 | }
362 |
363 | /// Returns the type of an operand as a `Types`
364 | ///
365 | /// # Arguments:
366 | /// * `operand` - The operand whose type is being returned.
367 | /// * `data` - Contains the `BasicBlockData` and all argument, temp, and variable declarations from
368 | /// the MIR pass.
369 | ///
370 | /// # Remarks:
371 | ///
372 | fn gen_ty(operand: &Operand, data: &mut MirData) -> Types {
373 | let type_string: String = match operand.clone() {
374 | Operand::Constant(ref constant) => constant.ty.to_string(),
375 | Operand::Consume(ref lvalue) => {
376 | match *lvalue {
377 | // Function argument
378 | Lvalue::Arg(ref arg) => data.arg_data[arg.index()].ty.to_string(),
379 | // Temporary variable
380 | Lvalue::Temp(ref temp) => data.temp_data[temp.index()].ty.to_string(),
381 | // Local variable
382 | Lvalue::Var(ref var) => data.var_data[var.index()].ty.to_string(),
383 | _ => unimplemented!(),
384 | }
385 | },
386 | };
387 |
388 | string_to_type(type_string)
389 | }
390 |
391 | /// Generates a version of wp "And"ed together with a conditional expression that mimics a check
392 | /// to ensure division by 0 does not occur.
393 | ///
394 | /// # Arguments:
395 | /// * `wp` - The current weakest precondition that the "div by 0" is to be "And"ed to
396 | /// * `exp` - The expression to check to make sure it is not divided by 0
397 | ///
398 | /// # Return Value:
399 | /// * Returns the modified weakest precondition with "div by 0" Expression "And"ed
400 | ///
401 | /// # Remarks:
402 | /// * Currently supported `ConstInt`: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`
403 | ///
404 | fn add_zero_check(wp: &Expression, exp: &Expression) -> Expression {
405 | let zero;
406 | if is_signed_type(determine_evaluation_type(exp)) {
407 | zero = Expression::SignedBitVector( SignedBitVectorData {
408 | // The bit-vector size of the given type
409 | size: match determine_evaluation_type(exp) {
410 | Types::I8 => 8,
411 | Types::I16 => 16,
412 | Types::I32 => 32,
413 | Types::I64 => 64,
414 | _ => rp_error!("Unimplemented checkeddAdd right-hand operand type"),
415 | },
416 | value: 0
417 | });
418 | } else {
419 | zero = Expression::UnsignedBitVector( UnsignedBitVectorData {
420 | // The bit-vector size of the given type
421 | size: match determine_evaluation_type(exp) {
422 | Types::U8 => 8,
423 | Types::U16 => 16,
424 | Types::U32 => 32,
425 | Types::U64 => 64,
426 | _ => rp_error!("Unimplemented checkeddAdd right-hand operand type"),
427 | },
428 | value: 0
429 | });
430 | }
431 |
432 | Expression::BinaryExpression( BinaryExpressionData{
433 | // And the weakest precondtion and the zero check
434 | op: BinaryOperator::And,
435 | left: Box::new(wp.clone()),
436 | right: Box::new(Expression::BinaryExpression( BinaryExpressionData{
437 | op: BinaryOperator::NotEqual,
438 | // The expression to be checked
439 | left: Box::new(exp.clone()),
440 | // Need to set appropriate type with value of 0
441 | right: Box::new(zero),
442 | }))
443 | })
444 | }
445 |
446 | /// Generates an appropriate variable mapping based on whatever variable, temp, or field is found
447 | ///
448 | /// # Arguments:
449 | /// * `lvalue` - The left value of an assignment to be generated into a `VariableMapping`
450 | /// * `data` - Contains the `BasicBlockData` and all argument, temp, and variable declarations from
451 | /// the MIR pass.
452 | ///
453 | /// # Return Value:
454 | /// * Returns a `VariableMappingData` that is built from `data` and `lvalue`
455 | ///
456 | /// # Remarks:
457 | ///
458 | fn gen_lvalue(lvalue: Lvalue, data: &mut MirData) -> VariableMappingData {
459 | match lvalue {
460 | // Function argument
461 | Lvalue::Arg(ref arg) => {
462 | // Find the name and type in the declaration
463 | VariableMappingData{
464 | name: data.arg_data[arg.index()].debug_name.as_str().to_string(),
465 | var_type: string_to_type(data.arg_data[arg.index()].ty.clone().to_string())
466 | }
467 | },
468 | // Temporary variable
469 | Lvalue::Temp(ref temp) => {
470 | // Find the index and type in the declaration
471 | let mut ty = data.temp_data[temp.index()].ty.clone().to_string();
472 | if let TypeVariants::TyTuple(t) = data.temp_data[temp.index()].ty.sty {
473 | if t.len() > 0 {
474 | ty = t[0].to_string();
475 | }
476 | }
477 | VariableMappingData{
478 | name: "tmp".to_string() + temp.index().to_string().as_str(),
479 | var_type: string_to_type(ty)
480 | }
481 | },
482 | // Local variable
483 | Lvalue::Var(ref var) => {
484 | // Find the name and type in the declaration
485 | VariableMappingData{
486 | name: "var".to_string() + var.index().to_string().as_str(),
487 | var_type: string_to_type(data.var_data[var.index()].ty.clone().to_string())
488 | }
489 | },
490 | // The returned value
491 | Lvalue::ReturnPointer => {
492 | VariableMappingData{
493 | name: "return".to_string(),
494 | var_type: data.func_return_type.clone()
495 | }
496 | },
497 | // (Most likely) a field of a tuple from a checked operation
498 | Lvalue::Projection(pro) => {
499 |
500 | // Get the index
501 | let index: String = match pro.as_ref().elem.clone() {
502 | // Index(ref o)
503 | ProjectionElem::Index(_) => unimplemented!(),
504 | // Field(ref field, ref ty)
505 | ProjectionElem::Field(ref field, _) => (field.index() as i32).to_string(),
506 | _ => unimplemented!(),
507 | };
508 |
509 | // Get the name of the variable being projected
510 | let lvalue_name;
511 | let lvalue_type_string;
512 |
513 | match pro.as_ref().base {
514 | // Argument
515 | Lvalue::Arg(ref arg) => {
516 | // Return the name of the argument
517 | lvalue_name = data.arg_data[arg.index()].debug_name.as_str().to_string();
518 | lvalue_type_string = data.arg_data[arg.index()].ty.clone().to_string();
519 | },
520 | // Temporary variable
521 | Lvalue::Temp(ref temp) => {
522 | // Return "temp"
523 | lvalue_name = "tmp".to_string() + temp.index().to_string().as_str();
524 |
525 | match data.temp_data[temp.index()].ty.sty {
526 | TypeVariants::TyTuple(t) => lvalue_type_string = t[0].to_string(),
527 | _ => unimplemented!(),
528 | }
529 | },
530 | // Local variable
531 | Lvalue::Var(ref var) => {
532 | // Return the name of the variable
533 | let i = index.parse::().unwrap();
534 | lvalue_name = "var".to_string() + var.index().to_string().as_str();
535 |
536 | match data.var_data[var.index()].ty.sty {
537 | TypeVariants::TyTuple(t) => lvalue_type_string = t[i].to_string(),
538 | _ => unimplemented!(),
539 | }
540 | },
541 | // Unimplemented Lvalue
542 | Lvalue::ReturnPointer => unimplemented!(),
543 | // Static(ref stat)
544 | Lvalue::Static(_) => unimplemented!(),
545 | // Multiply-nested projection
546 | Lvalue::Projection(_) => unimplemented!(),
547 | };
548 |
549 | // Get the index
550 | let index: String = match pro.as_ref().elem.clone() {
551 |
552 | // Field(ref field, ref ty)
553 | ProjectionElem::Field(ref field, _) => (field.index() as i32).to_string(),
554 | // Index(ref o)
555 | ProjectionElem::Index(_) => unimplemented!(),
556 | _ => unimplemented!(),
557 | };
558 |
559 | let lvalue_type: Types = string_to_type(lvalue_type_string);
560 |
561 | // Get the index int from index_operand, then stick it in the VariableMappingData
562 | VariableMappingData{ name: lvalue_name + "." + index.as_str(), var_type: lvalue_type }
563 | },
564 | _=> unimplemented!(),
565 | }
566 | }
567 |
568 | /// Generates an Expression based on some operand, either a literal or some kind of variable, temp,
569 | /// or field
570 | ///
571 | /// # Arguments:
572 | /// * `operand` - The operand to generate a new expression from.
573 | /// * `data` - Contains the `BasicBlockData` and all argument, temp, and variable declarations from
574 | /// the MIR pass.
575 | ///
576 | /// # Return Value:
577 | /// * Returns a new expression generated from an operand
578 | ///
579 | /// # Remarks:
580 | /// * Current supported types: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `bool`
581 | ///
582 | fn gen_expression(operand: &Operand, data: &mut MirData) -> Expression {
583 | match *operand {
584 | // A variable/temp/field
585 | Operand::Consume (ref l) => {
586 | Expression::VariableMapping( gen_lvalue(l.clone(), data) )
587 | },
588 | // A literal value
589 | Operand::Constant (ref c) => {
590 | match c.literal {
591 | Literal::Value {ref value} => {
592 | match *value {
593 | ConstVal::Bool(ref const_bool) => {
594 | Expression::BooleanLiteral(*const_bool)
595 | }
596 | ConstVal::Integral(ref const_int) => {
597 | match *const_int {
598 | ConstInt::I8(i) => {
599 | Expression::SignedBitVector( SignedBitVectorData {
600 | size: 8,
601 | value: i as i64
602 | } )
603 | },
604 | ConstInt::I16(i) => {
605 | Expression::SignedBitVector( SignedBitVectorData {
606 | size: 16,
607 | value: i as i64
608 | } )
609 | },
610 | ConstInt::I32(i) => {
611 | Expression::SignedBitVector( SignedBitVectorData {
612 | size: 32,
613 | value: i as i64
614 | } )
615 | },
616 | ConstInt::I64(i) => {
617 | Expression::SignedBitVector( SignedBitVectorData {
618 | size: 64,
619 | value: i as i64
620 | } )
621 | },
622 | ConstInt::U8(u) => {
623 | Expression::UnsignedBitVector( UnsignedBitVectorData {
624 | size: 8,
625 | value: u as u64
626 | } )
627 | },
628 | ConstInt::U16(u) => {
629 | Expression::UnsignedBitVector( UnsignedBitVectorData {
630 | size: 16,
631 | value: u as u64
632 | } )
633 | },
634 | ConstInt::U32(u) => {
635 | Expression::UnsignedBitVector( UnsignedBitVectorData {
636 | size: 32,
637 | value: u as u64
638 | } )
639 | },
640 | ConstInt::U64(u) => {
641 | Expression::UnsignedBitVector( UnsignedBitVectorData {
642 | size: 64,
643 | value: u as u64
644 | } )
645 | },
646 | _ => unimplemented!(),
647 | }
648 | },
649 | _ => unimplemented!(),
650 | }
651 | },
652 | // Item {ref def_id, ref substs}
653 | Literal::Item {..} => unimplemented!(),
654 | // Promoted {ref index}
655 | Literal::Promoted {..} => unimplemented!(),
656 | }
657 | },
658 | }
659 | }
660 |
--------------------------------------------------------------------------------
/src/weakest_precondition/overflow.rs:
--------------------------------------------------------------------------------
1 | // The Rust-Proof Project is copyright 2016, Sami Sahli,
2 | // Michael Salter, Matthew Slocum, Vincent Schuster,
3 | // Bradley Rasmussen, Drew Gohman, and Matthew O'Brien.
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 | //! Functions to generate overflow checks in the weakest precondition.
12 |
13 | extern crate rustc_const_math;
14 |
15 | use expression::*;
16 | use rustc::mir::repr::*;
17 |
18 |
19 | /// Routes to appropriate overflow check (signed / unsigned)
20 | // One catch-all function for overflow checking.
21 | pub fn overflow_check(wp: &Expression,
22 | var: &VariableMappingData,
23 | binop: &BinOp,
24 | lvalue: &Expression,
25 | rvalue: &Expression)
26 | -> Expression {
27 | Expression::BinaryExpression( BinaryExpressionData {
28 | op: BinaryOperator::And,
29 | left: Box::new(wp.clone()),
30 | right: Box::new(
31 | match var.var_type {
32 | Types::I8 => signed_overflow(binop, 8u8, lvalue, rvalue),
33 | Types::I16 => signed_overflow(binop, 16u8, lvalue, rvalue),
34 | Types::I32 => signed_overflow(binop, 32u8, lvalue, rvalue),
35 | Types::I64 => signed_overflow(binop, 64u8, lvalue, rvalue),
36 | Types::U8 | Types::U16 | Types::U32 | Types::U64 => {
37 | unsigned_overflow(binop, lvalue, rvalue)
38 | },
39 | _ => panic!("Unsupported return type of binary operation: {}", var.var_type),
40 | }
41 | ),
42 | })
43 | }
44 |
45 | /// Routes to appropriate overflow check
46 | // Signed: Match on the type of BinOp and call the correct function
47 | fn signed_overflow(binop: &BinOp, size: u8, lvalue: &Expression, rvalue: &Expression)
48 | -> Expression {
49 | match *binop {
50 | BinOp::Add => signed_add(size, lvalue, rvalue),
51 | BinOp::Mul => signed_mul(lvalue, rvalue),
52 | BinOp::Sub => signed_sub(size, lvalue, rvalue),
53 | BinOp::Div => signed_div(size, lvalue, rvalue),
54 | BinOp::Rem => signed_div(size, lvalue, rvalue),
55 | BinOp::Shl => unimplemented!(),
56 | BinOp::Shr => unimplemented!(),
57 | BinOp::BitOr => unimplemented!(),
58 | BinOp::BitAnd => unimplemented!(),
59 | BinOp::BitXor => unimplemented!(),
60 | BinOp::Lt => unimplemented!(),
61 | BinOp::Le => unimplemented!(),
62 | BinOp::Gt => unimplemented!(),
63 | BinOp::Ge => unimplemented!(),
64 | BinOp::Eq => unimplemented!(),
65 | BinOp::Ne => unimplemented!(),
66 | }
67 | }
68 |
69 | /// Creates an Expression containing overflow and underflow checks for lvalue + rvalue, assuming
70 | /// they are bitvectors of length "size"
71 | ///
72 | /// The following psuedocode provides a logically equivalent version of what is produced
73 | /// (false is returned if overflow/underflow has occurred, true otherwise)
74 | ///
75 | /// ```psuedo
76 | /// If lvalue >= 0 && rvalue >= 0
77 | /// If lvalue + rvalue < 0
78 | /// false
79 | /// Else
80 | /// true
81 | /// Else
82 | /// If lvalue < 0 && rvalue < 0
83 | /// If lvalue + rvalue >= 0
84 | /// false
85 | /// Else
86 | /// true
87 | /// Else
88 | /// true
89 | /// ```
90 | fn signed_add(size: u8, lvalue: &Expression, rvalue: &Expression) -> Expression {
91 | Expression::BinaryExpression( BinaryExpressionData{
92 | op: BinaryOperator::And,
93 | left: Box::new(
94 | Expression::BinaryExpression( BinaryExpressionData{
95 | op: BinaryOperator::Implication,
96 | left: Box::new(
97 | Expression::BinaryExpression( BinaryExpressionData{
98 | op: BinaryOperator::And,
99 | left: Box::new(
100 | Expression::BinaryExpression( BinaryExpressionData{
101 | op: BinaryOperator::GreaterThanOrEqual,
102 | left: Box::new(lvalue.clone()),
103 | right: Box::new(
104 | Expression::SignedBitVector( SignedBitVectorData {
105 | size: size,
106 | value: 0i64,
107 | })
108 | ),
109 | })
110 | ),
111 | right: Box::new(
112 | Expression::BinaryExpression( BinaryExpressionData{
113 | op: BinaryOperator::GreaterThanOrEqual,
114 | left: Box::new(rvalue.clone()),
115 | right: Box::new(
116 | Expression::SignedBitVector( SignedBitVectorData {
117 | size: size,
118 | value: 0i64,
119 | })
120 | ),
121 | })
122 | ),
123 | })
124 | ),
125 | right: Box::new(
126 | Expression::BinaryExpression( BinaryExpressionData{
127 | op: BinaryOperator::GreaterThanOrEqual,
128 | left: Box::new(
129 | Expression::BinaryExpression( BinaryExpressionData{
130 | op: BinaryOperator::Addition,
131 | left: Box::new(lvalue.clone()),
132 | right: Box::new(rvalue.clone()),
133 | })
134 | ),
135 | right: Box::new(
136 | Expression::SignedBitVector( SignedBitVectorData {
137 | size: size,
138 | value: 0i64,
139 | })
140 | ),
141 | })
142 | ),
143 | })
144 | ),
145 | right: Box::new(
146 | Expression::BinaryExpression( BinaryExpressionData{
147 | op: BinaryOperator::Implication,
148 | left: Box::new(
149 | Expression::BinaryExpression( BinaryExpressionData{
150 | op: BinaryOperator::Or,
151 | left: Box::new(
152 | Expression::BinaryExpression( BinaryExpressionData{
153 | op: BinaryOperator::LessThan,
154 | left: Box::new(lvalue.clone()),
155 | right: Box::new(
156 | Expression::SignedBitVector( SignedBitVectorData {
157 | size: size,
158 | value: 0i64,
159 | })
160 | ),
161 | })
162 | ),
163 | right: Box::new(
164 | Expression::BinaryExpression( BinaryExpressionData{
165 | op: BinaryOperator::LessThan,
166 | left: Box::new(rvalue.clone()),
167 | right: Box::new(
168 | Expression::SignedBitVector( SignedBitVectorData {
169 | size: size,
170 | value: 0i64,
171 | })
172 | ),
173 | })
174 | ),
175 | })
176 | ),
177 | right: Box::new(
178 | Expression::BinaryExpression( BinaryExpressionData{
179 | op: BinaryOperator::Implication,
180 | left: Box::new(
181 | Expression::BinaryExpression( BinaryExpressionData{
182 | op: BinaryOperator::And,
183 | left: Box::new(
184 | Expression::BinaryExpression( BinaryExpressionData{
185 | op: BinaryOperator::LessThan,
186 | left: Box::new(lvalue.clone()),
187 | right: Box::new(
188 | Expression::SignedBitVector( SignedBitVectorData {
189 | size: size,
190 | value: 0i64,
191 | })
192 | ),
193 | })
194 | ),
195 | right: Box::new(
196 | Expression::BinaryExpression( BinaryExpressionData{
197 | op: BinaryOperator::LessThan,
198 | left: Box::new(rvalue.clone()),
199 | right: Box::new(
200 | Expression::SignedBitVector( SignedBitVectorData {
201 | size: size,
202 | value: 0i64,
203 | })
204 | ),
205 | })
206 | ),
207 | })
208 | ),
209 | right: Box::new(
210 | Expression::BinaryExpression( BinaryExpressionData{
211 | op: BinaryOperator::LessThan,
212 | left: Box::new(
213 | Expression::BinaryExpression( BinaryExpressionData{
214 | op: BinaryOperator::Addition,
215 | left: Box::new(lvalue.clone()),
216 | right: Box::new(rvalue.clone()),
217 | })
218 | ),
219 | right: Box::new(
220 | Expression::SignedBitVector( SignedBitVectorData {
221 | size: size,
222 | value: 0i64,
223 | })
224 | ),
225 | })
226 | ),
227 | })
228 | ),
229 | })
230 | ),
231 | })
232 | }
233 |
234 | /// Creates an Expression containing overflow and underflow checks for lvalue - rvalue, assuming
235 | /// they are bitvectors of length "size"
236 | ///
237 | /// The following psuedocode provides a logically equivalent version of what is produced
238 | /// (false is returned if overflow/underflow has occurred, true otherwise)
239 | ///
240 | /// ```psuedo
241 | /// If lvalue >= 0 && rvalue < 0
242 | /// If lvalue - rvalue < 0
243 | /// false
244 | /// Else
245 | /// true
246 | /// Else
247 | /// If lvalue < 0 && rvalue >= 0
248 | /// If lvalue - rvalue >= 0
249 | /// false
250 | /// Else
251 | /// true
252 | /// Else
253 | /// true
254 | /// ```
255 | fn signed_sub(size: u8, lvalue: &Expression, rvalue: &Expression) -> Expression {
256 | Expression::BinaryExpression( BinaryExpressionData{
257 | op: BinaryOperator::And,
258 | left: Box::new(
259 | Expression::BinaryExpression( BinaryExpressionData{
260 | op: BinaryOperator::Implication,
261 | left: Box::new(
262 | Expression::BinaryExpression( BinaryExpressionData{
263 | op: BinaryOperator::And,
264 | left: Box::new(
265 | Expression::BinaryExpression( BinaryExpressionData{
266 | op: BinaryOperator::GreaterThanOrEqual,
267 | left: Box::new(lvalue.clone()),
268 | right: Box::new(
269 | Expression::SignedBitVector( SignedBitVectorData {
270 | size: size,
271 | value: 0i64,
272 | })
273 | ),
274 | })
275 | ),
276 | right: Box::new(
277 | Expression::BinaryExpression( BinaryExpressionData{
278 | op: BinaryOperator::LessThan,
279 | left: Box::new(rvalue.clone()),
280 | right: Box::new(
281 | Expression::SignedBitVector( SignedBitVectorData {
282 | size: size,
283 | value: 0i64,
284 | })
285 | ),
286 | })
287 | ),
288 | })
289 | ),
290 | right: Box::new(
291 | Expression::BinaryExpression( BinaryExpressionData{
292 | op: BinaryOperator::GreaterThanOrEqual,
293 | left: Box::new(
294 | Expression::BinaryExpression( BinaryExpressionData{
295 | op: BinaryOperator::Subtraction,
296 | left: Box::new(lvalue.clone()),
297 | right: Box::new(rvalue.clone()),
298 | })
299 | ),
300 | right: Box::new(
301 | Expression::SignedBitVector( SignedBitVectorData {
302 | size: size,
303 | value: 0i64,
304 | })
305 | ),
306 | })
307 | ),
308 | })
309 | ),
310 | right: Box::new(
311 | Expression::BinaryExpression( BinaryExpressionData{
312 | op: BinaryOperator::Implication,
313 | left: Box::new(
314 | Expression::BinaryExpression( BinaryExpressionData{
315 | op: BinaryOperator::Or,
316 | left: Box::new(
317 | Expression::BinaryExpression( BinaryExpressionData{
318 | op: BinaryOperator::LessThan,
319 | left: Box::new(lvalue.clone()),
320 | right: Box::new(
321 | Expression::SignedBitVector( SignedBitVectorData {
322 | size: size,
323 | value: 0i64,
324 | })
325 | ),
326 | })
327 | ),
328 | right: Box::new(
329 | Expression::BinaryExpression( BinaryExpressionData{
330 | op: BinaryOperator::GreaterThanOrEqual,
331 | left: Box::new(rvalue.clone()),
332 | right: Box::new(
333 | Expression::SignedBitVector( SignedBitVectorData {
334 | size: size,
335 | value: 0i64,
336 | })
337 | ),
338 | })
339 | ),
340 | })
341 | ),
342 | right: Box::new(
343 | Expression::BinaryExpression( BinaryExpressionData{
344 | op: BinaryOperator::Implication,
345 | left: Box::new(
346 | Expression::BinaryExpression( BinaryExpressionData{
347 | op: BinaryOperator::And,
348 | left: Box::new(
349 | Expression::BinaryExpression( BinaryExpressionData{
350 | op: BinaryOperator::LessThan,
351 | left: Box::new(lvalue.clone()),
352 | right: Box::new(
353 | Expression::SignedBitVector( SignedBitVectorData {
354 | size: size,
355 | value: 0i64,
356 | })
357 | ),
358 | })
359 | ),
360 | right: Box::new(
361 | Expression::BinaryExpression( BinaryExpressionData{
362 | op: BinaryOperator::GreaterThanOrEqual,
363 | left: Box::new(rvalue.clone()),
364 | right: Box::new(
365 | Expression::SignedBitVector( SignedBitVectorData {
366 | size: size,
367 | value: 0i64,
368 | })
369 | ),
370 | })
371 | ),
372 | })
373 | ),
374 | right: Box::new(
375 | Expression::BinaryExpression( BinaryExpressionData{
376 | op: BinaryOperator::LessThan,
377 | left: Box::new(
378 | Expression::BinaryExpression( BinaryExpressionData{
379 | op: BinaryOperator::Subtraction,
380 | left: Box::new(lvalue.clone()),
381 | right: Box::new(rvalue.clone()),
382 | })
383 | ),
384 | right: Box::new(
385 | Expression::SignedBitVector( SignedBitVectorData {
386 | size: size,
387 | value: 0i64,
388 | })
389 | ),
390 | })
391 | ),
392 | })
393 | ),
394 | })
395 | ),
396 | })
397 | }
398 |
399 | fn signed_mul(lvalue: &Expression, rvalue: &Expression) -> Expression {
400 | let overflow: Expression = Expression::BinaryExpression( BinaryExpressionData{
401 | op: BinaryOperator::SignedMultiplicationDoesNotOverflow,
402 | left: Box::new(lvalue.clone()),
403 | right: Box::new(rvalue.clone()),
404 | });
405 |
406 | let underflow: Expression = Expression::BinaryExpression( BinaryExpressionData{
407 | op: BinaryOperator::SignedMultiplicationDoesNotUnderflow,
408 | left: Box::new(lvalue.clone()),
409 | right: Box::new(rvalue.clone()),
410 | });
411 |
412 | Expression::BinaryExpression( BinaryExpressionData{
413 | op: BinaryOperator::And,
414 | left: Box::new(overflow),
415 | right: Box::new(underflow),
416 | })
417 | }
418 |
419 | fn signed_div(size: u8, lvalue: &Expression, rvalue: &Expression) -> Expression {
420 | let condition = Expression::BinaryExpression( BinaryExpressionData{
421 | op: BinaryOperator::And,
422 | left: Box::new(
423 | Expression::BinaryExpression( BinaryExpressionData{
424 | op: BinaryOperator::Equal,
425 | left: Box::new(lvalue.clone()),
426 | right: Box::new(
427 | Expression::SignedBitVector( SignedBitVectorData{
428 | size: size,
429 | value: match size {
430 | 8u8 => i8::min_value() as i64,
431 | 16u8 => i16::min_value() as i64,
432 | 32u8 => i32::min_value() as i64,
433 | 64u8 => i64::min_value() as i64,
434 | _ => panic!("unsupported integer type"),
435 | },
436 | })
437 | ),
438 | })
439 | ),
440 | right: Box::new(
441 | Expression::BinaryExpression( BinaryExpressionData{
442 | op: BinaryOperator::Equal,
443 | left: Box::new(rvalue.clone()),
444 | right: Box::new(
445 | Expression::SignedBitVector( SignedBitVectorData{
446 | size: size,
447 | value: -1i64,
448 | })
449 | )
450 | })
451 | ),
452 | });
453 |
454 | Expression::BinaryExpression( BinaryExpressionData{
455 | op: BinaryOperator::And,
456 | left: Box::new(
457 | Expression::BinaryExpression( BinaryExpressionData{
458 | op: BinaryOperator::Implication,
459 | left: Box::new(condition.clone()),
460 | right: Box::new(
461 | Expression::BooleanLiteral(false)
462 | ),
463 | })
464 | ),
465 | right: Box::new(
466 | Expression::BinaryExpression( BinaryExpressionData{
467 | op: BinaryOperator::Implication,
468 | left: Box::new(
469 | Expression::UnaryExpression( UnaryExpressionData{
470 | op: UnaryOperator::Not,
471 | e: Box::new(condition.clone()),
472 | })
473 | ),
474 | right: Box::new(
475 | Expression::BooleanLiteral(true)
476 | ),
477 | })
478 | ),
479 | })
480 | }
481 |
482 | /// Routes to appropriate overflow check
483 | // Unsigned: Match on the type of BinOp and call the correct function
484 | fn unsigned_overflow(binop: &BinOp, lvalue: &Expression, rvalue: &Expression) -> Expression {
485 | match *binop {
486 | BinOp::Add => unsigned_add(lvalue, rvalue),
487 | BinOp::Sub => unsigned_sub(lvalue, rvalue),
488 | BinOp::Mul => unsigned_mul(lvalue, rvalue),
489 | BinOp::Div => unreachable!(),
490 | BinOp::Rem => unreachable!(),
491 | BinOp::Shl => unimplemented!(),
492 | BinOp::Shr => unimplemented!(),
493 | BinOp::BitOr => unimplemented!(),
494 | BinOp::BitAnd => unimplemented!(),
495 | BinOp::BitXor => unimplemented!(),
496 | BinOp::Lt => unimplemented!(),
497 | BinOp::Le => unimplemented!(),
498 | BinOp::Gt => unimplemented!(),
499 | BinOp::Ge => unimplemented!(),
500 | BinOp::Eq => unimplemented!(),
501 | BinOp::Ne => unimplemented!(),
502 | }
503 | }
504 |
505 | fn unsigned_mul(lvalue: &Expression, rvalue: &Expression) -> Expression {
506 | Expression::BinaryExpression( BinaryExpressionData{
507 | op: BinaryOperator::UnsignedMultiplicationDoesNotOverflow,
508 | left: Box::new(lvalue.clone()),
509 | right: Box::new(rvalue.clone()),
510 | })
511 | }
512 |
513 | // l + r >= l
514 | fn unsigned_add(lvalue: &Expression, rvalue: &Expression) -> Expression {
515 | Expression::BinaryExpression( BinaryExpressionData{
516 | op: BinaryOperator::GreaterThanOrEqual,
517 | //l + r
518 | left: Box::new(
519 | Expression::BinaryExpression( BinaryExpressionData{
520 | op: BinaryOperator::Addition,
521 | left: Box::new(lvalue.clone()),
522 | right: Box::new(rvalue.clone()),
523 | })
524 | ),
525 | // r
526 | right: Box::new(rvalue.clone()),
527 | })
528 | }
529 |
530 | // Evaluates true when no overflow occurs
531 | // l-r <= l ||
532 | // l-r <= r
533 | fn unsigned_sub(lvalue: &Expression, rvalue: &Expression) -> Expression {
534 | // l-r <= l || l-r <= r
535 | Expression::BinaryExpression( BinaryExpressionData{
536 | op: BinaryOperator::Or,
537 | left: Box::new(
538 | // l-r <= l
539 | Expression::BinaryExpression( BinaryExpressionData{
540 | op: BinaryOperator::LessThanOrEqual,
541 | // l - r
542 | left: Box::new(
543 | Expression::BinaryExpression( BinaryExpressionData{
544 | op: BinaryOperator::Subtraction,
545 | left: Box::new(lvalue.clone()),
546 | right: Box::new(rvalue.clone()),
547 | })
548 | ),
549 | // l
550 | right: Box::new(lvalue.clone()),
551 | })
552 | ),
553 | right: Box::new(
554 | // l-r <= r
555 | Expression::BinaryExpression( BinaryExpressionData{
556 | op: BinaryOperator::LessThanOrEqual,
557 | // l - r
558 | left: Box::new(
559 | Expression::BinaryExpression( BinaryExpressionData{
560 | op: BinaryOperator::Subtraction,
561 | left: Box::new(lvalue.clone()),
562 | right: Box::new(rvalue.clone()),
563 | })
564 | ),
565 | // r
566 | right: Box::new(rvalue.clone()),
567 | })
568 | )
569 | })
570 |
571 |
572 |
573 | }
574 |
--------------------------------------------------------------------------------
/tests/test_assert.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // Should be valid
8 | #[condition(pre="x: i32 == 10i32", post="true")]
9 | fn valid_simple_assertion(x: i32) {
10 | assert!(x > 0);
11 | }
12 |
13 | // Should be invalid
14 | #[condition(pre="x: i32 == 10i32", post="true")]
15 | fn invalid_simple_assertion(x: i32) {
16 | assert!(x < 10);
17 | }
18 |
19 |
20 | //FIXME: This portion doesn't work currently.
21 | /*
22 | // Should be valid
23 | #[condition(pre="x: i32 == 10i32", post="true")]
24 | fn valid_simple_assertion_eq(x: i32) {
25 | assert_eq!(x, 10);
26 | }
27 |
28 | // Should be invalid
29 | #[condition(pre="x: i32 == 10i32", post="true")]
30 | fn invalid_simple_assertion_eq(x: i32) {
31 | assert_eq!(x, 0);
32 | }
33 | */
34 |
--------------------------------------------------------------------------------
/tests/test_boolean_arithmetic.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() {}
6 |
7 | // * * *
8 | // Boolean and Boolean Operator Tests
9 | // * * *
10 |
11 | // Should be valid
12 | #[condition(pre="true", post="true")]
13 | fn valid_basic_boolean() -> bool {
14 | true
15 | }
16 |
17 | // Should be invalid
18 | #[condition(pre="true", post="false")]
19 | fn invalid_basic_boolean()-> bool {
20 | true
21 | }
22 |
23 | // Should be valid
24 | #[condition(pre="x:bool == true", post="return:bool == true")]
25 | fn valid_boolean_and_logical(x:bool) -> bool {
26 | x && true
27 | }
28 |
29 | // Should be invalid
30 | #[condition(pre="x:bool == true", post="return:bool == true")]
31 | fn invalid_boolean_and_logical(x:bool) -> bool {
32 | x && false
33 | }
34 |
35 | // Should be valid
36 | #[condition(pre="x:bool == true", post="return:bool == true")]
37 | fn valid_boolean_and_bitwise(x:bool) -> bool {
38 | x & true
39 | }
40 |
41 | // Should be invalid
42 | #[condition(pre="x:bool == true", post="return:bool == true")]
43 | fn invalid_boolean_and_bitwise(x:bool) -> bool {
44 | x & false
45 | }
46 |
47 | // Should be valid
48 | #[condition(pre="x:bool == true", post="return:bool == true")]
49 | fn valid_boolean_or_logical(x:bool) -> bool {
50 | x || true
51 | }
52 | // Should be invalid
53 | #[condition(pre="x:bool == true", post="return:bool == false")]
54 | fn invalid_boolean_or_logical(x:bool) -> bool {
55 | x || true
56 | }
57 |
58 | // Should be valid
59 | #[condition(pre="x:bool == true", post="return:bool == true")]
60 | fn valid_boolean_or_bitwise(x:bool) -> bool {
61 | x | true
62 | }
63 | // Should be invalid
64 | #[condition(pre="x:bool == true", post="return:bool == false")]
65 | fn invalid_boolean_or_bitwise(x:bool) -> bool {
66 | x | true
67 | }
68 |
69 | // Should be valid
70 | #[condition(pre="x:bool == true", post="return:bool == false")]
71 | fn valid_boolean_not_variable(x:bool) -> bool {
72 | !x
73 | }
74 |
75 | // Should be invalid
76 | #[condition(pre="x:bool == true", post="return:bool == true")]
77 | fn invalid_boolean_not_variable(x:bool) -> bool {
78 | !x
79 | }
80 |
81 | // Should be valid
82 | #[condition(pre="x:bool == true", post="return: bool == false")]
83 | fn valid_boolean_not_literal() -> bool {
84 | !true
85 | }
86 |
87 | // Should be invalid
88 | #[condition(pre="x:bool == true", post="return: bool == true")]
89 | fn invalid_boolean_not_literal() -> bool {
90 | !true
91 | }
92 |
93 | // Should be valid
94 | #[condition(pre="x:bool == true", post="return: bool == false")]
95 | fn valid_boolean_xor_bitwise(x: bool) -> bool {
96 | x ^ true
97 | }
98 |
99 | // Should be invalid
100 | #[condition(pre="x:bool == true", post="return: bool == true")]
101 | fn invalid_boolean_xor_bitwise(x : bool) -> bool {
102 | x ^ true
103 | }
104 |
105 | // Should be valid
106 | #[condition(pre="true",post="true AND true")]
107 | fn valid_attr_condition_and_and()-> bool {
108 | true
109 | }
110 |
111 | // Should be valid
112 | #[condition(pre="true",post="true && true")]
113 | fn valid_attr_condition_and_logical()-> bool {
114 | true
115 | }
116 |
117 | // Should be valid
118 | #[condition(pre="true",post="true & true")]
119 | fn valid_attr_condition_and_bitwise()-> bool {
120 | true
121 | }
122 |
123 | // Should be valid
124 | #[condition(pre="true",post="true OR true")]
125 | fn valid_attr_condition_or_or()-> bool {
126 | true
127 | }
128 |
129 | // Should be valid
130 | #[condition(pre="true",post="true || true")]
131 | fn valid_attr_condition_or_logical()-> bool {
132 | true
133 | }
134 |
135 | // Should be valid
136 | #[condition(pre="true",post="true | true")]
137 | fn valid_attr_condition_or_bitwise()-> bool {
138 | true
139 | }
140 |
141 | // Should be valid
142 | #[condition(pre="true",post="true ^ false")]
143 | fn valid_attr_condition_xor_bitwise()-> bool {
144 | true
145 | }
146 |
147 | // Should be valid
148 | #[condition(pre="true",post="true XOR false")]
149 | fn valid_attr_condition_xor_xor()-> bool {
150 | true
151 | }
152 |
153 |
154 | // Should be valid
155 | #[condition(pre="x: bool == true", post="return:bool == true")]
156 | fn valid_simple_bool_and(x:bool) -> bool {
157 | x && true
158 | }
159 |
160 | // Should be valid
161 | #[condition(pre="x: bool == false", post="return:bool == false")]
162 | fn valid_simple_bool_or(x:bool) -> bool {
163 | x || false
164 | }
165 |
166 | // Should be invalid
167 | #[condition(pre="x: bool == true", post="return:bool == false")]
168 | fn invalid_simple_bool_and_2(x:bool) -> bool {
169 | x && true
170 | }
171 |
172 | // Should be invalid
173 | #[condition(pre="x: bool == false", post="return:bool == true")]
174 | fn invalid_simple_bool_or_2(x:bool) -> bool {
175 | x || false
176 | }
177 |
178 | // * * *
179 | // test ! Operator
180 | // * * *
181 |
182 | //should be invalid
183 | #[condition(pre="x: bool == true", post="return:bool == true")]
184 | fn invalid_simple_bool_not(x:bool) -> bool {
185 | !x && true
186 | }
187 |
188 | // Should be invalid
189 | #[condition(pre="x: bool == false", post="return:bool == false")]
190 | fn invalid_simple_bool_not_2(x:bool) -> bool {
191 | !x || false
192 | }
193 |
194 | // * * *
195 | // test & and | operator
196 | // * * *
197 |
198 | #[condition(pre="x: bool == true", post="return:bool == true")]
199 | fn valid_simple_bool_bitwise_and(x:bool) -> bool {
200 | x & true
201 | }
202 |
203 | // Should be invalid
204 | #[condition(pre="x: bool == false", post="return:bool == false")]
205 | fn invalid_simple_bool_bitwise_or(x:bool) -> bool {
206 | x | true
207 | }
208 |
209 | // Should be invalid
210 | #[condition(pre="x: bool == true", post="return:bool == true")]
211 | fn invalid_simple_bool_bitwise_and_2(x:bool) -> bool {
212 | x & false
213 | }
214 |
215 | // Should be valid
216 | #[condition(pre="x: bool == true", post="return:bool == true")]
217 | fn valid_simple_bool_bitwise_or_2(x:bool) -> bool {
218 | x | false
219 | }
220 |
221 | // * * *
222 | // Additional Tests
223 | // * * *
224 |
225 | // Should be valid
226 | #[condition(pre="x: bool == false", post="return:bool == true")]
227 | fn valid_simple_bool_bitwise_or_if_else(x:bool) -> bool {
228 | if x {
229 | x | false
230 | } else {
231 | x | true
232 | }
233 | }
234 |
235 | // Should be valid
236 | #[condition(pre="(x: bool == true) || (x: bool == false)", post="return:bool == true")]
237 | fn valid_simple_bool_pre_or(x:bool) -> bool {
238 | if x {
239 | true
240 | } else {
241 | true
242 | }
243 | }
244 |
245 | // Should be invalid
246 | #[condition(pre="(x: bool == true) && (y: bool == false)", post="return:bool == false")]
247 | fn invalid_bool_pre_and(x:bool, y:bool) -> bool {
248 | if x | y {
249 | true
250 | } else {
251 | false
252 | }
253 | }
254 |
255 | // Should be valid
256 | #[condition(pre="x: bool == true", post="(return:bool == true) || (return:bool == false)")]
257 | fn valid_bool_post_or(x:bool) -> bool {
258 | x | false
259 | }
260 |
261 | // Should be valid
262 | #[condition(pre="(x: bool == true) && (y: bool == false) && (z: bool == true)", post="return:bool == true")]
263 | fn valid_bool_complex(x:bool, y:bool, z:bool) -> bool {
264 | let mut a = 4;
265 |
266 | if z {
267 | a = a + 5;
268 | } else {
269 | a = a + 10;
270 | }
271 |
272 | if a > 9 && y {
273 | return true;
274 | } else {
275 | if x {
276 | return true;
277 | }
278 | else {
279 | return false;
280 | }
281 | }
282 | }
283 |
284 | // Should be invalid
285 | #[condition(pre="(w: i32 >= 6i32) && (x: bool == false) && (y: bool == true) && (z: bool == true)", post="return:bool == true")]
286 | fn invalid_bool_complex(x:bool, y:bool, z:bool, w:i32) -> bool {
287 | let mut a = 4;
288 | if w > 5 {
289 | return false;
290 | }
291 | if z {
292 | a = a + 5;
293 | } else {
294 | a = a + 10;
295 | }
296 |
297 | if a > 9 && y {
298 | return true;
299 | } else {
300 | if x {
301 | return true;
302 | } else {
303 | return false;
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/tests/test_conditionals.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | fn main() {}
5 |
6 | // Tests that should return 'valid'
7 | #[condition(pre="(x: i32 < i32::MAX - 6i32) && (y: bool == false)", post="return: i32 == (x: i32 + 6i32)")]
8 | fn valid_variable_conditional(x: i32, y: bool) -> i32 {
9 | if y {
10 | x + 5
11 | } else {
12 | x + 6
13 | }
14 | }
15 |
16 | #[condition(pre="x: i32 < i32::MAX - 6i32", post="return: i32 == (x: i32 + 6i32)")]
17 | fn valid_literal_conditional(x: i32) -> i32 {
18 | if false {
19 | x + 5
20 | } else {
21 | x + 6
22 | }
23 | }
24 |
25 | #[condition(pre="(x: i32 < i32::MAX - 6i32) && (x: i32 < 5i32)", post="return: i32 == (x: i32 + 6i32)")]
26 | fn valid_expression_conditional(x: i32) -> i32 {
27 | if x > 5 {
28 | x + 5
29 | } else {
30 | x + 6
31 | }
32 | }
33 |
34 | #[condition(pre="x: i32 == 5i32", post="return: i32 == (x: i32 + 6i32)")]
35 | fn valid_triple_branch_conditional(x: i32) -> i32 {
36 | if x > 5 {
37 | x + 5
38 | } else if x < 5 {
39 | x + 7
40 | } else {
41 | x + 6
42 | }
43 | }
44 |
45 | #[condition(pre="(x: i32 == 4i32) && (y: bool == false)", post="return: i32 == (x: i32 + 6i32)")]
46 | fn valid_nested_conditionals(x: i32, y: bool) -> i32 {
47 | if y {
48 | x + 5
49 | } else {
50 | if x > 5 {
51 | x + 7
52 | } else {
53 | x + 6
54 | }
55 | }
56 | }
57 |
58 | // Tests that should return 'invalid'
59 | #[condition(pre="(x: i32 < i32::MAX - 6i32) && (y: bool == true)", post="return: i32 == (x: i32 + 6i32)")]
60 | fn invalid_variable_conditional(x: i32, y: bool) -> i32 {
61 | if y {
62 | x + 5
63 | } else {
64 | x + 6
65 | }
66 | }
67 |
68 | #[condition(pre="x: i32 < i32::MAX - 6i32", post="return: i32 == (x: i32 + 6i32)")]
69 | fn invalid_literal_conditional(x: i32) -> i32 {
70 | if true {
71 | x + 5
72 | } else {
73 | x + 6
74 | }
75 | }
76 |
77 | #[condition(pre="(x: i32 < i32::MAX - 6i32) && (x: i32 < 5i32)", post="return: i32 == (x: i32 + 6i32)")]
78 | fn invalid_expression_conditional(x: i32) -> i32 {
79 | if x < 5 {
80 | x + 5
81 | } else {
82 | x + 6
83 | }
84 | }
85 |
86 | #[condition(pre="x: i32 == 5i32", post="return: i32 == (x: i32 + 6i32)")]
87 | fn invalid_triple_branch_conditional(x: i32) -> i32 {
88 | if x > 5 {
89 | x + 5
90 | } else if x == 5 {
91 | x + 7
92 | } else {
93 | x + 6
94 | }
95 | }
96 |
97 | #[condition(pre="(x: i32 == 4i32) && (y: bool == false)", post="return: i32 == (x: i32 + 6i32)")]
98 | fn invalid_nested_conditionals(x: i32, y: bool) -> i32 {
99 | if y {
100 | x + 5
101 | } else {
102 | if x < 5 {
103 | x + 7
104 | } else {
105 | x + 6
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/tests/test_conditions.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // FIXME: some preconditions are unnecisarilly restricitve ie add_five_i32_invalid does not need x: i32 >= i32::MIN + 5i32
8 |
9 | // * * *
10 | // Integer Add Tests
11 | // * * *
12 |
13 | // Tests signed integer overflow for 32 bit integers
14 | // Should be invalid
15 | #[condition(pre="(x: i32 <= i32::MAX - 4i32) && (x: i32 >= i32::MIN + 5i32)", post="return: i32 == (x: i32 + 5i32)")]
16 | fn invalid_add_five_i32(x: i32) -> i32 {
17 | x+5
18 | }
19 |
20 | // Tests signed integer overflow for 32 bit integers
21 | // Should be valid
22 | #[condition(pre="(x: i32 <= i32::MAX - 5i32) && (x: i32 >= i32::MIN + 5i32)", post="return: i32 == (x: i32 + 5i32)")]
23 | fn valid_add_five_i32(x: i32) -> i32 {
24 | x+5
25 | }
26 |
27 | // Tests signed integer overflow for 64 bit integers
28 | // Should be invalid
29 | #[condition(pre="(x: i64 <= i64::MAX - 4i64) && (x: i64 >= i64::MIN + 5i64)", post="return: i64 == (x: i64 + 5i64)")]
30 | fn invalid_add_five_i64(x: i64) -> i64 {
31 | x+5
32 | }
33 |
34 | // Tests signed integer overflow for 64 bit integers
35 | // Should be valid
36 | #[condition(pre="(x: i64 <= i64::MAX - 5i64) && (x: i64 >= i64::MIN + 5i64)", post="return: i64 == (x: i64 + 5i64)")]
37 | fn valid_add_five_i64(x: i64) -> i64 {
38 | x+5
39 | }
40 |
41 | // Tests unsigned integer overflow for 32 bit integers
42 | // Should be invalid
43 | #[condition(pre="x: u32 <= u32::MAX - 4u32", post="return: u32 == (x: u32 + 5u32)")]
44 | fn invalid_add_five_u32(x: u32) -> u32 {
45 | x+5
46 | }
47 |
48 | // Tests unsigned integer overflow for 32 bit integers
49 | // Should be valid
50 | #[condition(pre="x: u32 <= u32::MAX - 5u32", post="return: u32 == (x: u32 + 5u32)")]
51 | fn valid_add_five_u32(x: u32) -> u32 {
52 | x+5
53 | }
54 |
55 | // * * *
56 | // Assertion Tests
57 | // * * *
58 |
59 | // Should be valid
60 | #[condition(pre="true", post="true")]
61 | fn valid_asrt_basic() {
62 | assert!(1 > 0)
63 | }
64 |
65 | // Should be invalid
66 | #[condition(pre="true", post="true")]
67 | fn invalid_asrt_basic() {
68 | assert!(1 < 0)
69 | }
70 |
71 | // FIXME ERROR This test fails to compile.
72 | // Should be valid
73 | //#[condition(pre="x:bool == true", post="true")]
74 | fn valid_asrt_argument(x: bool) {
75 | assert!(x)
76 | }
77 |
78 | // * * *
79 | // Conditional Branch Tests
80 | // * * *
81 |
82 | // Should be valid
83 | #[condition(pre="true", post="true")]
84 | fn valid_basic_literal_if() {
85 | if true {
86 | assert!(1 > 0)
87 | } else {
88 | assert!(1 < 0)
89 | }
90 | }
91 |
92 | //Matt's example. Should be invalid. Calling it valid
93 | #[condition(pre="true",post="true")]
94 | fn invalid_fake_function(){
95 | if true {
96 | assert!(1<0)
97 | } else {
98 | assert!(1>0)
99 | }
100 | }
101 |
102 | // Should be invalid
103 | #[condition(pre="true", post="true")]
104 | fn invalid_basic_literal_if() {
105 | if true {
106 | assert!(1 < 0)
107 | } else {
108 | assert!(1 > 0)
109 | }
110 | }
111 |
112 | // Should be valid
113 | #[condition(pre="true", post="true")]
114 | fn valid_large_branch_literal_if() {
115 | if false {
116 | assert!(1 < 0)
117 | } else if true {
118 | assert!(1 > 0)
119 | } else {
120 | assert!(1 < 0)
121 | }
122 | }
123 |
124 | // Should be invalid
125 | #[condition(pre="true", post="true")]
126 | fn invalid_large_branch_literal_if() {
127 | if false {
128 | assert!(1 < 0)
129 | } else if false {
130 | assert!(1 > 0)
131 | } else {
132 | assert!(1 < 0)
133 | }
134 | }
135 |
136 | // * * *
137 | // Boolean Tests
138 | // * * *
139 |
140 | // Should be valid
141 | #[condition(pre="x:bool == true", post="true")]
142 | fn valid_boolean_comparison_in_condition(x:bool) -> bool {
143 | x
144 | }
145 |
146 | // Should be invalid
147 | #[condition(pre="x:bool == true", post="false")]
148 | fn invalid_boolean_comparison_in_condition(x:bool) -> bool {
149 | x
150 | }
151 |
152 | // Should be valid
153 | #[condition(pre="true", post="return:bool == true")]
154 | fn valid_simple_bool(x:bool) -> bool {
155 | x || true
156 | }
157 |
158 | // Should be valid
159 | #[condition(pre="x:bool == true", post="return:bool == true")]
160 | fn valid_boolean_condition(x:bool) -> bool {
161 | if x {
162 | true
163 | } else {
164 | false
165 | }
166 | }
167 |
168 | // Should be invalid
169 | #[condition(pre="x:bool == false", post="return:bool == true")]
170 | fn invalid_boolean_condition(x:bool) -> bool {
171 | if x {
172 | true
173 | } else {
174 | false
175 | }
176 | }
177 |
178 |
--------------------------------------------------------------------------------
/tests/test_fail_invalid.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // Used to test the tester
8 |
9 | // Condition is valid, and function name indicates "invalid", so should be detected as a mismatch
10 | #[condition(pre="x: i32 <= i32::MAX - 5i32", post="return: i32 == (x: i32 + 5i32)")]
11 | fn invalid_add_five_i32(x: i32) -> i32 {
12 | x+5
13 | }
14 |
--------------------------------------------------------------------------------
/tests/test_fail_valid.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // Used to test the tester
8 |
9 | // Condition is invalid, and function name indicates "valid", so should be detected as a mismatch
10 | #[condition(pre="x: i32 <= i32::MAX - 4i32", post="return: i32 == (x: i32 + 5i32)")]
11 | fn valid_add_five_i32(x: i32) -> i32 {
12 | x+5
13 | }
14 |
--------------------------------------------------------------------------------
/tests/test_signed.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // * * *
8 | // Signed Integer Operator Tests
9 | // * * *
10 |
11 | // Tests signed integer for 32 bit integers
12 | // Should be invalid
13 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 > 5i32")]
14 | fn invalid_add_five_i32(x: i32) -> i32 {
15 | x + 5
16 | }
17 |
18 | // Tests signed integer for 32 bit integers
19 | // Should be valid
20 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 > 4i32")]
21 | fn valid_add_five_i32(x: i32) -> i32 {
22 | x + 5
23 | }
24 |
25 | // Tests signed integer for 32 bit integers
26 | // Should be invalid
27 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 > 0i32")]
28 | fn invalid_add_five_negative_i32(x: i32) -> i32 {
29 | x + 5
30 | }
31 |
32 | // Tests signed integer for 32 bit integers
33 | // Should be valid
34 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 > -6i32")]
35 | fn valid_add_five_negative_i32(x: i32) -> i32 {
36 | x + 5
37 | }
38 |
39 | // Tests signed integer for 32 bit integers
40 | // Should be invalid
41 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 > 4i32")]
42 | fn invalid_subtract_five_i32(x: i32) -> i32 {
43 | x - 5
44 | }
45 |
46 | // Tests signed integer for 32 bit integers
47 | // Should be valid
48 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 < 6i32")]
49 | fn valid_subtract_five_i32(x: i32) -> i32 {
50 | x - 5
51 | }
52 |
53 | // Tests signed integer for 32 bit integers
54 | // Should be invalid
55 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 > 0i32")]
56 | fn invalid_subtract_five_negative_i32(x: i32) -> i32 {
57 | x - 5
58 | }
59 |
60 | // Tests signed integer for 32 bit integers
61 | // Should be valid
62 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 < -2i32")]
63 | fn valid_subtract_five_negative_i32(x: i32) -> i32 {
64 | x - 5
65 | }
66 |
67 | // Tests signed integer for 32 bit integers
68 | // Should be invalid
69 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 < 0i32")]
70 | fn invalid_multiply_five_i32(x: i32) -> i32 {
71 | x * 5i32
72 | }
73 |
74 | // Tests signed integer for 32 bit integers
75 | // Should be valid
76 | #[condition(pre="(x: i32 <= 10i32) && (x: i32 >= 0i32)", post="return: i32 >= 0i32")]
77 | fn valid_multiply_five_i32(x: i32) -> i32 {
78 | x * 5
79 | }
80 |
81 | // Tests signed integer for 32 bit integers
82 | // Should be invalid
83 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 == -2i32")]
84 | fn invalid_multiply_five_negative_i32(x: i32) -> i32 {
85 | x * 5
86 | }
87 |
88 | // Tests signed integer for 32 bit integers
89 | // Should be valid
90 | #[condition(pre="(x: i32 < 0i32) && (x: i32 >= -10i32)", post="return: i32 < 0i32")]
91 | fn valid_multiply_five_negative_i32(x: i32) -> i32 {
92 | x * 5
93 | }
94 |
95 | // Tests signed integer for 32 bit integers
96 | // Should be invalid
97 | #[condition(pre="(x: i32 >= 0i32) && (x: i32 <= 10i32)", post="return: i32 >= 0i32")]
98 | fn invalid_divide_five_i32(x: i32) -> i32 {
99 | 5 / x
100 | }
101 |
102 |
103 | // Tests signed integer for 32 bit integers
104 | // Should be valid
105 | #[condition(pre="(x: i32 > 0i32) && (x: i32 <= 10i32)", post="return: i32 >= 0i32")]
106 | fn valid_divide_five_i32(x: i32) -> i32 {
107 | 2 / x
108 | }
109 |
110 | // Tests signed integer for 32 bit integers
111 | // Should be invalid
112 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 > 1i32")]
113 | fn invalid_divide_five_negative_i32(x: i32) -> i32 {
114 | x / 2
115 | }
116 |
117 | // Tests signed integer for 32 bit integers
118 | // Should be valid
119 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 < 1i32")]
120 | fn valid_divide_five_negative_i32(x: i32) -> i32 {
121 | x / 2
122 | }
123 |
124 | // Tests signed integer for 32 bit integers
125 | // Should be invalid
126 | #[condition(pre="(x: i32 >= 0i32) && (x: i32 <= 10i32)", post="return: i32 < 0i32")]
127 | fn invalid_mod_five_i32(x: i32) -> i32 {
128 | x % 5
129 | }
130 |
131 | // Tests signed integer for 32 bit integers
132 | // Should be valid
133 | #[condition(pre="(x: i32 > 0i32) && (x: i32 <= 10i32)", post="return: i32 >= 0i32")]
134 | fn valid_mod_five_i32(x: i32) -> i32 {
135 | x % 5
136 | }
137 |
138 | // Tests signed integer for 32 bit integers
139 | // Should be invalid
140 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 > 1i32")]
141 | fn invalid_mod_five_negative_i32(x: i32) -> i32 {
142 | x % 5
143 | }
144 |
145 | // Tests signed integer for 32 bit integers
146 | // Should be valid
147 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 < 10i32")]
148 | fn valid_mod_five_negative_i32(x: i32) -> i32 {
149 | x % 5
150 | }
151 |
152 | // Tests signed integer for 32 bit integers
153 | // Should be invalid
154 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 > 10i32")]
155 | fn invalid_unary_minus_five_i32(x: i32) -> i32 {
156 | x + (-(5))
157 | }
158 |
159 | // Tests signed integer for 32 bit integers
160 | // Should be valid
161 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 < 10i32")]
162 | fn valid_unary_minus_five_i32(x: i32) -> i32 {
163 | x + (-(5))
164 | }
165 |
166 | // Tests signed integer for 32 bit integers
167 | // Should be invalid
168 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 > 0i32")]
169 | fn invalid_unary_minus_negative_five_i32(x: i32) -> i32 {
170 | x + (-(5))
171 | }
172 |
173 | // Tests signed integer for 32 bit integers
174 | // Should be valid
175 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 < 0i32")]
176 | fn valid_unary_minus_five_negative_i32(x: i32) -> i32 {
177 | x + (-(5))
178 | }
179 |
180 | // Tests signed integer for 32 bit integers
181 | // Should be invalid
182 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 < 0i32")]
183 | fn invalid_bit_shift_left_two_i32(x: i32) -> i32 {
184 | x << 2i32
185 | }
186 |
187 | // Tests signed integer for 32 bit integers
188 | // Should be valid
189 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 > 0i32")]
190 | fn valid_bit_shift_left_two_i32(x: i32) -> i32 {
191 | x << 2i32
192 | }
193 |
194 | // Tests signed integer for 32 bit integers
195 | // Should be invalid
196 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 > 0i32")]
197 | fn invalid_bit_shift_left_two_negative_i32(x: i32) -> i32 {
198 | x << 2i32
199 | }
200 |
201 | // Tests signed integer for 32 bit integers
202 | // Should be valid
203 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 < 2i32")]
204 | fn valid_bit_shift_left_two_negative_i32(x: i32) -> i32 {
205 | x << 2i32
206 | }
207 |
208 |
209 | // Tests signed integer for 32 bit integers
210 | // Should be invalid
211 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 > 0i32")]
212 | fn invalid_bit_shift_right_two_i32(x: i32) -> i32 {
213 | x >> 2i32
214 | }
215 |
216 | // Tests signed integer for 32 bit integers
217 | // Should be valid
218 | #[condition(pre="(x: i32 > 0i32) && (x: i32 < 10i32)", post="return: i32 >= 0i32")]
219 | fn valid_bit_shift_right_two_i32(x: i32) -> i32 {
220 | x >> 2i32
221 | }
222 |
223 | // Tests signed integer for 32 bit integers
224 | // Should be invalid
225 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 > 0i32")]
226 | fn invalid_bit_shift_right_negative_two_i32(x: i32) -> i32 {
227 | x >> 2i32
228 | }
229 |
230 | // Tests signed integer for 32 bit integers
231 | // Should be valid
232 | #[condition(pre="(x: i32 < 0i32) && (x: i32 > -10i32)", post="return: i32 <= 0i32")]
233 | fn valid_bit_shift_right_two_negative_i32(x: i32) -> i32 {
234 | x >> 2i32
235 | }
236 |
237 | // Tests signed integer for 16 bit integers
238 | // Should be valid
239 | #[condition(pre="(x: i8 < 10i8) && (x: i8 > 0i8)", post="return: i8 > 3i8")]
240 | fn valid_add_5_i8(x: i8) -> i8 {
241 | x+5i8
242 | }
243 |
244 |
245 | // Tests signed integer for 16 bit integers
246 | // Should be valid
247 | #[condition(pre="(x: i16 < 10i16) && (x: i16 > 0i16)", post="return: i16 > 3i16")]
248 | fn valid_add_5_i16(x: i16) -> i16 {
249 | x+5
250 | }
251 |
252 | // Tests signed integer for 64 bit integers
253 | // Should be valid
254 | #[condition(pre="(x: i64 < 10i64) && (x: i64 > 0i64)", post="return: i64 > 3i64")]
255 | fn valid_add_5_i64(x: i64) -> i64 {
256 | x+5
257 | }
258 |
259 | // Overflow Tests
260 |
261 | // Tests signed integer for 32 bit integers
262 | // Should be invalid
263 | #[condition(pre="(x: i32 == i32::MAX)", post="return: i32 > 0i32")]
264 | fn invalid_add_five_overflow_i32(x: i32) -> i32 {
265 | x + 5
266 | }
267 |
268 | // Tests signed integer for 32 bit integers
269 | // Should be invalid
270 | #[condition(pre="(x: i32 == i32::MIN)", post="return: i32 < 0i32")]
271 | fn invalid_subtract_five_overflow_i32(x: i32) -> i32 {
272 | x - 5
273 | }
274 |
275 | // Tests signed integer for 32 bit integers
276 | // Should be invalid
277 | #[condition(pre="(x: i32 == i32::MIN)", post="return: i32 > 0i32")]
278 | fn invalid_divide_one_overflow_i32(x: i32) -> i32 {
279 | x / -1
280 | }
281 |
282 | // Tests signed integer for 32 bit integers
283 | // Should be invalid
284 | #[condition(pre="(x: i32 == i32::MIN)", post="return: i32 > 0i32")]
285 | fn invalid_mod_one_overflow_i32(x: i32) -> i32 {
286 | x % -1
287 | }
288 |
289 | // Tests signed integer for 32 bit integers
290 | // Should be invalid
291 | #[condition(pre="(x: i32 == i32::MAX)", post="return: i32 > 0i32")]
292 | fn invalid_multiply_five_overflow_i32(x: i32) -> i32 {
293 | x * 5
294 | }
295 |
296 | // Tests signed integer for 16 bit integers
297 | // Should be invalid
298 | #[condition(pre="(x: i16 == i16::MAX)", post="return: i16 > 0i16")]
299 | fn invalid_add_five_overflow_i16(x: i16) -> i16 {
300 | x + 5
301 | }
302 |
303 | // Tests signed integer for 16 bit integers
304 | // Should be invalid
305 | #[condition(pre="(x: i16 == i16::MIN)", post="return: i16 < 0i16")]
306 | fn invalid_subtract_five_overflow_i16(x: i16) -> i16 {
307 | x - 5
308 | }
309 |
310 | // Tests signed integer for 8 bit integers
311 | // Should be invalid
312 | #[condition(pre="(x: i8 == i8::MAX)", post="return: i8 > 0i8")]
313 | fn invalid_add_five_overflow_i8(x: i8) -> i8 {
314 | x + 5
315 | }
316 |
317 | // Tests signed integer for 8 bit integers
318 | // Should be invalid
319 | #[condition(pre="(x: i8 == i8::MIN)", post="return: i8 < 0i8")]
320 | fn invalid_subtract_five_overflow_i8(x: i8) -> i8 {
321 | x - 5
322 | }
323 |
324 | // Tests signed integer for 64 bit integers
325 | // Should be invalid
326 | #[condition(pre="(x: i64 == i64::MAX)", post="return: i64 > 0i64")]
327 | fn invalid_add_five_overflow_i64(x: i64) -> i64 {
328 | x + 5
329 | }
330 |
331 | // Tests signed integer for 64 bit integers
332 | // Should be invalid
333 | #[condition(pre="(x: i64 == i64::MIN)", post="return: i64 < 0i64")]
334 | fn invalid_subtract_five_overflow_i64(x: i64) -> i64 {
335 | x - 5
336 | }
337 |
--------------------------------------------------------------------------------
/tests/test_unsigned.rs:
--------------------------------------------------------------------------------
1 | #![feature(plugin, custom_attribute)]
2 | #![plugin(rustproof)]
3 | #![allow(dead_code)]
4 | #![allow(unused_attributes)]
5 | fn main() { }
6 |
7 | // * * *
8 | // Unsigned Integer Operator Tests
9 | // * * *
10 |
11 | // Tests unsigned integer for 32 bit integers
12 | // Should be invalid
13 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 >= 0u32)", post="return: u32 > 5u32")]
14 | fn invalid_add_five_u32(x: u32) -> u32 {
15 | x + 5
16 | }
17 |
18 | // Tests unsigned integer for 32 bit integers
19 | // Should be valid
20 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 >= 0u32)", post="return: u32 > 4u32")]
21 | fn valid_add_five_u32(x: u32) -> u32 {
22 | x + 5
23 | }
24 |
25 | // Tests unsigned integer for 32 bit integers
26 | // Should be invalid
27 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 >= 0u32)", post="return: u32 > 10u32")]
28 | fn invalid_subtract_five_u32(x: u32) -> u32 {
29 | x - 5
30 | }
31 |
32 | // Tests unsigned integer for 32 bit integers
33 | // Should be valid
34 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 > 5u32)", post="return: u32 < 6u32")]
35 | fn valid_subtract_five_u32(x: u32) -> u32 {
36 | x - 5
37 | }
38 |
39 | // Test to check unsigned subtration underflow
40 | // Should be valid
41 | #[condition(pre="x:u64 == 7u64", post="return:u64 == 5u64")]
42 | fn valid_subtraction_underflow(x:u64) -> u64 {
43 | return x-2;
44 | }
45 |
46 | // Tests unsigned integer for 32 bit integers
47 | // Should be invalid
48 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 >= 0u32)", post="return: u32 < 0u32")]
49 | fn invalid_multiply_five_u32(x: u32) -> u32 {
50 | x * 5u32
51 | }
52 |
53 | // Tests unsigned integer for 32 bit integers
54 | // Should be valid
55 | #[condition(pre="(x: u32 <= 10u32) && (x: u32 >= 0u32)", post="return: u32 >= 0u32")]
56 | fn valid_multiply_five_u32(x: u32) -> u32 {
57 | x * 5
58 | }
59 |
60 | // Tests unsigned integer for 32 bit integers
61 | // Should be invalid
62 | #[condition(pre="(x: u32 >= 0u32) && (x: u32 <= 10u32)", post="return: u32 >= 0u32")]
63 | fn invalid_divide_five_u32(x: u32) -> u32 {
64 | 5 / x
65 | }
66 |
67 | // Tests unsigned integer for 32 bit integers
68 | // Should be valid
69 | #[condition(pre="(x: u32 > 0u32) && (x: u32 <= 10u32)", post="return: u32 >= 0u32")]
70 | fn valid_divide_five_u32(x: u32) -> u32 {
71 | 2 / x
72 | }
73 |
74 | // Tests unsigned integer for 32 bit integers
75 | // Should be invalid
76 | #[condition(pre="(x: u32 >= 0u32) && (x: u32 <= 10u32)", post="return: u32 < 0u32")]
77 | fn invalid_mod_five_u32(x: u32) -> u32 {
78 | x % 5
79 | }
80 |
81 | // Tests unsigned integer for 32 bit integers
82 | // Should be valid
83 | #[condition(pre="(x: u32 > 0u32) && (x: u32 <= 10u32)", post="return: u32 >= 0u32")]
84 | fn valid_mod_five_u32(x: u32) -> u32 {
85 | x % 5
86 | }
87 |
88 | // Tests unsigned integer for 32 bit integers
89 | // Should be invalid
90 | #[condition(pre="(x: u32 > 0u32) && (x: u32 < 10u32)", post="return: u32 < 0u32")]
91 | fn invalid_bit_shift_left_two_u32(x: u32) -> u32 {
92 | x << 2u32
93 | }
94 |
95 | // Tests unsigned integer for 32 bit integers
96 | // Should be valid
97 | #[condition(pre="(x: u32 > 0u32) && (x: u32 < 10u32)", post="return: u32 > 0u32")]
98 | fn valid_bit_shift_left_two_u32(x: u32) -> u32 {
99 | x << 2u32
100 | }
101 |
102 | // Tests unsigned integer for 32 bit integers
103 | // Should be invalid
104 | #[condition(pre="(x: u32 > 0u32) && (x: u32 < 10u32)", post="return: u32 > 0u32")]
105 | fn invalid_bit_shift_right_two_u32(x: u32) -> u32 {
106 | x >> 2u32
107 | }
108 |
109 | // Tests unsigned integer for 32 bit integers
110 | // Should be valid
111 | #[condition(pre="(x: u32 > 0u32) && (x: u32 < 10u32)", post="return: u32 >= 0u32")]
112 | fn valid_bit_shift_right_two_u32(x: u32) -> u32 {
113 | x >> 2u32
114 | }
115 |
116 | // Tests unsigned integer for 16 bit integers
117 | // Should be valid
118 | #[condition(pre="(x: u8 < 10u8) && (x: u8 > 0u8)", post="return: u8 > 3u8")]
119 | fn valid_add_5_u8(x: u8) -> u8 {
120 | x+5u8
121 | }
122 |
123 | // Tests unsigned integer for 16 bit integers
124 | // Should be valid
125 | #[condition(pre="(x: u16 < 10u16) && (x: u16 > 0u16)", post="return: u16 > 3u16")]
126 | fn valid_add_5_u16(x: u16) -> u16 {
127 | x+5
128 | }
129 |
130 | // Tests unsigned integer for 64 bit integers
131 | // Should be valid
132 | #[condition(pre="(x: u64 < 10u64) && (x: u64 > 0u64)", post="return: u64 > 3u64")]
133 | fn valid_add_5_u64(x: u64) -> u64 {
134 | x+5
135 | }
136 |
137 | // Tests signed integer for 32 bit integers
138 | // Should be invalid
139 | #[condition(pre="(x: u32 == u32::MAX)", post="return: u32 > 20u32")]
140 | fn invalid_add_five_overflow_u32(x: u32) -> u32 {
141 | x + 5
142 | }
143 |
144 | // Tests signed integer for 32 bit integers
145 | // Should be invalid
146 | #[condition(pre="(x: u32 == u32::MIN)", post="return: u32 < 20u32")]
147 | fn invalid_subtract_five_overflow_u32(x: u32) -> u32 {
148 | x - 5
149 | }
150 |
151 | // Tests signed integer for 32 bit integers
152 | // Should be invalid
153 | #[condition(pre="(x: u32 == u32::MAX)", post="true")]
154 | fn invalid_multiply_two_overflow_u32(x: u32) -> u32 {
155 | x * 2
156 | }
157 |
158 | // Tests signed integer for 16 bit integers
159 | // Should be invalid
160 | #[condition(pre="(x: u16 == u16::MAX)", post="return: u16 > 20u16")]
161 | fn invalid_add_five_overflow_u16(x: u16) -> u16 {
162 | x + 5
163 | }
164 |
165 | // Tests signed integer for 16 bit integers
166 | // Should be invalid
167 | #[condition(pre="(x: u16 == u16::MIN)", post="return: u16 < 20u16")]
168 | fn invalid_subtract_five_overflow_u16(x: u16) -> u16 {
169 | x - 5
170 | }
171 |
172 | // Tests signed integer for 8 bit integers
173 | // Should be invalid
174 | #[condition(pre="(x: u8 == u8::MAX)", post="return: u8 > 20u8")]
175 | fn invalid_add_five_overflow_u8(x: u8) -> u8 {
176 | x + 5
177 | }
178 |
179 | // Tests signed integer for 8 bit integers
180 | // Should be invalid
181 | #[condition(pre="(x: u8 == u8::MIN)", post="return: u8 < 20u8")]
182 | fn invalid_subtract_five_overflow_u8(x: u8) -> u8 {
183 | x - 5
184 | }
185 |
186 | // Tests signed integer for 64 bit integers
187 | // Should be invalid
188 | #[condition(pre="(x: u64 == u64::MAX)", post="return: u64 > 20u64")]
189 | fn invalid_add_five_overflow_u64(x: u64) -> u64 {
190 | x + 5
191 | }
192 |
193 | // Tests signed integer for 64 bit integers
194 | // Should be invalid
195 | #[condition(pre="(x: u64 == u64::MIN)", post="return: u64 < 20u64")]
196 | fn invalid_subtract_five_overflow_u64(x: u64) -> u64 {
197 | x - 5
198 | }
199 |
--------------------------------------------------------------------------------