|
1 | 1 | # Rust Model Checker (RMC)
|
2 | 2 | The Rust Model Checker (RMC) aims to be a bit-precise model-checker for Rust.
|
3 | 3 |
|
4 |
| -## Project Status |
5 |
| -RMC is currently in the initial development phase. |
6 |
| -It **does not yet support all Rust language features**. |
7 |
| -We are working to extend our support of language features. |
8 |
| -If you encounter issues when using RMC we encourage you to |
9 |
| -[report them to us](https://github.com/model-checking/rmc/issues/new/choose). |
10 |
| - |
11 |
| -## Quickstart |
12 |
| - |
13 |
| -1. Install the dependencies needed for [`rustc`](https://github.com/rust-lang/rust), |
14 |
| - [CBMC](https://github.com/diffblue/cbmc) and |
15 |
| - [CBMC Viewer](https://github.com/awslabs/aws-viewer-for-cbmc/releases/latest). |
16 |
| - |
17 |
| - The [RMC Installation Guide](https://model-checking.github.io/rmc/install-guide.html) |
18 |
| - shows how to quickly install them using our setup scripts. |
19 |
| - |
20 |
| -1. Configure RMC. |
21 |
| - We recommend using the following options: |
22 |
| - ``` |
23 |
| - ./configure \ |
24 |
| - --enable-debug \ |
25 |
| - --set=llvm.download-ci-llvm=true \ |
26 |
| - --set=rust.debug-assertions-std=false \ |
27 |
| - --set=rust.deny-warnings=false |
28 |
| - ``` |
29 |
| - |
30 |
| -1. Build RMC |
31 |
| - ``` |
32 |
| - ./x.py build -i --stage 1 library/std |
33 |
| - ``` |
34 |
| - |
35 |
| -1. Run the RMC test-suite |
36 |
| - ``` |
37 |
| - ./scripts/rmc-regression.sh |
38 |
| - ``` |
39 |
| - |
40 |
| -## Running RMC |
41 |
| -RMC currently supports command-line invocation on single files. |
42 |
| -We are actively working to integrate RMC into `cargo` (see [experimental Cargo integration](#experimental-cargo-integration)). |
43 |
| -Until then, the easiest way to use RMC is as follows |
44 |
| - |
45 |
| - |
46 |
| -1. Add `rmc/scripts` to your path |
47 |
| -1. Go to a folder that contains a rust file you would like to verify with RMC. |
48 |
| - For example, `cd rmc/src/test/rmc/Parenths`. |
49 |
| - By default, `rmc` uses `main()` as the entry point. |
50 |
| -1. Execute RMC on the file |
51 |
| - ``` |
52 |
| - rmc main.rs |
53 |
| - ``` |
54 |
| - You should see output that looks like the following |
55 |
| - ``` |
56 |
| - ** Results: |
57 |
| - main.rs function main |
58 |
| - [main.assertion.1] line 7 attempt to compute `move _6 + const 1_i32`, which would overflow: SUCCESS |
59 |
| - [main.assertion.2] line 7 attempt to compute `move _4 * move _5`, which would overflow: SUCCESS |
60 |
| - [main.assertion.3] line 8 assertion failed: c == 88: SUCCESS |
61 |
| - [main.assertion.4] line 11 attempt to compute `move _16 * move _17`, which would overflow: SUCCESS |
62 |
| - [main.assertion.5] line 11 attempt to compute `move _15 + const 1_i32`, which would overflow: SUCCESS |
63 |
| - [main.assertion.6] line 11 attempt to compute `move _14 * move _20`, which would overflow: SUCCESS |
64 |
| - [main.assertion.7] line 12 assertion failed: e == 10 * (500 + 5): SUCCESS |
65 |
| - ``` |
66 |
| -1. Write your own test file, add your own assertions, and try it out! |
67 |
| - |
68 |
| -### Using your Config.toml to configure RMC |
69 |
| - |
70 |
| -When invoking RMC using `cargo rmc`, you can use your Config.toml to configure the flags for RMC. |
71 |
| -If you want to configure your project to use the following command: |
72 |
| - |
73 |
| -`cargo rmc --c-lib src/lib/harness.c src/lib/api.c src/lib/utils.c --function test_all_rmc --no-memory-safety-checks --verbose --target-dir dev/target --visualize` |
74 |
| - |
75 |
| -Then you could put the following into your Cargo.toml: |
76 |
| - |
77 |
| -``` |
78 |
| -... |
79 |
| -[rmc.flags] |
80 |
| -c-lib = [ |
81 |
| - "src/lib/harness.c", |
82 |
| - "src/lib/api.c" |
83 |
| - "src/lib/utils.c" |
84 |
| -] |
85 |
| -function = "test_all_rmc" |
86 |
| -memory-safety-checks = false |
87 |
| -verbose = true |
88 |
| -target-dir = "dev/target" |
89 |
| -visualize = true |
90 |
| -... |
91 |
| -``` |
92 |
| -and invoke RMC with `cargo rmc /path/to/project`. |
93 |
| - |
94 |
| -You can additionally specify a different toml file to use with the `--config-toml` or disable this feature with `--no-config-toml`. |
95 |
| - |
96 |
| -Lastly, you can override specific flags from command line, e.g. with `cargo rmc /path/to/project --function test_different_rmc`. |
97 |
| - |
98 |
| -### Advanced flags |
99 |
| -RMC supports a set of advanced flags that give you control over the verification process. |
100 |
| -For example, consider the `CopyIntrinsics` regression test: |
101 |
| -1. `cd rmc/src/test/rmc/CopyIntrinsics` |
102 |
| -1. Execute RMC on the file |
103 |
| - `rmc main.rs` |
104 |
| -1. Note that this will unwind forever |
105 |
| - ``` |
106 |
| - Unwinding loop memcmp.0 iteration 1 file <builtin-library-memcmp> line 25 function memcmp thread 0 |
107 |
| - Unwinding loop memcmp.0 iteration 2 file <builtin-library-memcmp> line 25 function memcmp thread 0 |
108 |
| - Unwinding loop memcmp.0 iteration 3 file <builtin-library-memcmp> line 25 function memcmp thread 0 |
109 |
| - Unwinding loop memcmp.0 iteration 4 file <builtin-library-memcmp> line 25 function memcmp thread 0 |
110 |
| - Unwinding loop memcmp.0 iteration 5 file <builtin-library-memcmp> line 25 function memcmp thread 0 |
111 |
| - ... |
112 |
| - ``` |
113 |
| -1. You can pass additional arguments to the CBMC backend using the syntax: |
114 |
| - ``` |
115 |
| - rmc filename.rs --cbmc-args <additional CBMC arguments> |
116 |
| - ``` |
117 |
| - To see which arguments CBMC supports, run `cbmc --help`. |
118 |
| - In this case, we want the `--unwind` argument to limit the unwinding. |
119 |
| - We also use the `--unwinding-assertions` argument to ensure that our unwind bounds are sufficient. |
120 |
| - Note that: |
121 |
| - ``` |
122 |
| - rmc main.rs --cbmc-args --unwind 1 --unwinding-assertions |
123 |
| - ``` |
124 |
| - produces an unwinding failure, while |
125 |
| - ``` |
126 |
| - rmc main.rs --cbmc-args --unwind 17 --unwinding-assertions |
127 |
| - ``` |
128 |
| - leads to all assertions passing. |
129 |
| -1. You can check for undefined behaviour using builtin checks from CBMC. |
130 |
| - Try using `--pointer-check`, or `--unsigned-overflow-check`. |
131 |
| - You can see the full list of available checks by running `cbmc --help`. |
132 |
| - |
133 |
| -### Looking under the hood |
134 |
| -1. To see "under the hood" of what RMC is doing, try passing the `--gen-c` flag to RMC |
135 |
| - ``` |
136 |
| - rmc --gen-c main.rs <other-args> |
137 |
| - ``` |
138 |
| - This generates a file `main.c` which contains a "C" like formatting of the CBMC IR. |
139 |
| -1. The `--gen-c` flag does not produce runnable C code due to differences in the Rust and C languages. |
140 |
| - To produce a runnable C program, try passing the `--gen-c-runnable` flag to RMC |
141 |
| - ``` |
142 |
| - rmc --gen-c-runnable main.rs <other-args> |
143 |
| - ``` |
144 |
| - This generates a file `main_runnable.c`. |
145 |
| - Note that this makes some compromises to produce runnable C code, so you should not expect exact semantic equivalence. |
146 |
| -1. You can also view the raw CBMC internal representation using the `--keep-temps` option. |
147 |
| - |
148 |
| -### Experimental Cargo integration |
149 |
| - |
150 |
| -We are actively working to improve RMC's integration with Rust's Cargo package and build system. Currently, you can build projects with Cargo via a multi-step process. |
151 |
| - |
152 |
| -For example, we will describe using RMC as a backend to build the [`rand-core` crate](https://crates.io/crates/rand_core). These instructions have been tested on Ubuntu Linux with the `x86_64-unknown-linux-gnu` target. |
153 |
| - |
154 |
| -1. Build RMC |
155 |
| - ``` |
156 |
| - ./x.py build -i --stage 1 library/std |
157 |
| - ``` |
158 |
| - |
159 |
| -2. Clone `rand` and navigate to the `rand-core` directory: |
160 |
| - ``` |
161 |
| - git clone [email protected]:rust-random/rand.git |
162 |
| - cd rand/rand_core |
163 |
| - ``` |
164 |
| -3. Next, we need to add an entry-point for CBMC to the crate's source. For now, we will just pick an existing unit test. Open `src/le.rs` and find the `test_read` function at the bottom of the file. Add the following attribute to keep the function name unmangled, so we can later pass it to CBMC. |
165 |
| - |
166 |
| - ```rust |
167 |
| - // #[test] <- Remove/comment out this |
168 |
| - #[no_mangle] // <- Add this |
169 |
| - fn test_read() { |
170 |
| - let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
171 |
| - |
172 |
| - let mut buf = [0u32; 4]; |
173 |
| - read_u32_into(&bytes, &mut buf); |
174 |
| - assert_eq!(buf[0], 0x04030201); |
175 |
| - assert_eq!(buf[3], 0x100F0E0D); |
176 |
| - // ... |
177 |
| - } |
178 |
| - ``` |
179 |
| - |
180 |
| -4. Now, we can run Cargo and specify that RMC should be the backend. We also pass a location for the build artifacts (`rand-core-demo`) and a target (`x86_64-unknown-linux-gnu`). |
181 |
| - ``` |
182 |
| - CARGO_TARGET_DIR=rand-core-demo RUST_BACKTRACE=1 RUSTFLAGS="-Z codegen-backend=gotoc --cfg=rmc" RUSTC=rmc-rustc cargo build --target x86_64-unknown-linux-gnu |
183 |
| - ``` |
184 |
| - |
185 |
| -5. Now, navigate to the output directory for the given target. |
186 |
| - ``` |
187 |
| - cd rand-core-demo/x86_64-unknown-linux-gnu/debug/deps/ |
188 |
| - ``` |
189 |
| - |
190 |
| -6. The output of Cargo with RMC is a series of JSON files that define CMBC symbols. We now can use CBMC commands to convert and link these files: |
191 |
| - ``` |
192 |
| - symtab2gb rand_core-*.json --out a.out // Convert from JSON to Gotoc |
193 |
| - goto-cc --function test_read a.out -o a.out // Add the entry point we previously selected |
194 |
| - goto-instrument --drop-unused-functions a.out a.out // Remove unused functions |
195 |
| - cbmc a.out // Run CBMC |
196 |
| - ``` |
197 |
| - |
198 |
| -You should then see verification succeed: |
199 |
| -``` |
200 |
| -** 0 of 43 failed (1 iterations) |
201 |
| -VERIFICATION SUCCESSFUL |
202 |
| -``` |
203 |
| - |
204 |
| -To sanity-check that verification is working, try changing ` assert_eq!(buf[0], 0x04030201);` to a different value and rerun these commands. |
205 |
| - |
206 |
| -For crates with multiple JSON files in the `deps` folder, we suggest running the first command in this step with [`parallel`](https://www.gnu.org/software/parallel/): |
207 |
| - ``` |
208 |
| - ls *.json | parallel -j 16 symtab2gb {} --out {.}.out // Convert from JSON to Gotoc |
209 |
| - ``` |
| 4 | +Check out the [Documentation](https://model-checking.github.io/rmc) for |
| 5 | +instructions on installing and running RMC. |
210 | 6 |
|
211 | 7 | ## Security
|
212 | 8 | See [SECURITY](https://github.com/model-checking/rmc/security/policy) for more information.
|
213 | 9 |
|
214 | 10 | ## Developer guide
|
215 |
| -See [DEVELOPER-GUIDE.md](DEVELOPER-GUIDE.md). |
| 11 | +See [RMC developer documentation](https://model-checking.github.io/rmc/dev-documentation.html). |
216 | 12 |
|
217 | 13 | ## License
|
218 | 14 | ### Rust compiler
|
|
0 commit comments