Skip to content

Commit 54e5d36

Browse files
ranjitjhalanilehmann
authored andcommitted
Add Flux entry to the book
1 parent 7a89027 commit 54e5d36

File tree

3 files changed

+241
-1
lines changed

3 files changed

+241
-1
lines changed

doc/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- [Kani](./tools/kani.md)
1111
- [GOTO Transcoder](./tools/goto-transcoder.md)
1212
- [VeriFast](./tools/verifast.md)
13+
- [Flux](./tools/flux.md)
1314

1415
---
1516

doc/src/tools/flux.md

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# Flux
2+
3+
[Flux](https://flux-rs.github.io/flux) is a refinement type checker
4+
that can be used to prove user-defined safety properties for Rust.
5+
Users can write their own properties via refinement type contracts
6+
(a generalization of pre- and post-conditions). Additionally, out of the
7+
box, Flux checks for various issues such as
8+
9+
- arithmetic overflows
10+
- division by zero
11+
- array bounds violations
12+
13+
## Installation
14+
15+
See the [installation section of the Flux book](https://flux-rs.github.io/flux/install.html)
16+
to learn how to install and run Flux.
17+
18+
19+
## Usage
20+
21+
(Adapted from the Kani documentation; see [the Flux book](https://flux-rs.github.io/flux)
22+
for many more examples.)
23+
24+
Consider a Rust file `demo.rs` with a function that returns
25+
the absolute value of the difference between two integers.
26+
To *prove* that the function always returns a *non-negative* result, you write
27+
a Flux specification—above the function definition—that says the output
28+
is a refinement type `i32{v: 0 <= v}` denoting non-negative `i32` values.
29+
30+
31+
``` rust
32+
// demo.rs
33+
#[allow(dead_code)]
34+
#[cfg_attr(flux, flux::spec(fn(a: i32, b: i32) -> i32{v:0 <= v}))]
35+
fn test_abs(a:i32, b:i32) -> i32 {
36+
if a > b {
37+
a - b
38+
} else {
39+
b - a
40+
}
41+
}
42+
```
43+
44+
Now, if you run
45+
46+
```
47+
$ flux --crate-type=lib demo.rs
48+
```
49+
50+
Flux will return immediately with **no output** indicating the code is safe.
51+
52+
This may be baffling for those with a keen understanding of arithmetic overflows:
53+
what if `a` is `INT_MAX` and `b` is `INT_MIN`? Indeed, Flux has overflow checking
54+
off by default but you can optionally switch it on for a function, module, or entire crate.
55+
56+
``` rust
57+
// demo.rs
58+
#[allow(dead_code)]
59+
#[cfg_attr(flux, flux::opts(check_overflow = true))]
60+
#[cfg_attr(flux, flux::spec(fn(a: i32, b: i32) -> i32{v:0 <= v}))]
61+
fn test_abs(a:i32, b:i32) -> i32 {
62+
if a > b {
63+
a - b
64+
} else {
65+
b - a
66+
}
67+
}
68+
```
69+
70+
Now, when you run `flux` you see that
71+
72+
```
73+
$ flux --crate-type=lib demo.rs
74+
error[E0999]: arithmetic operation may overflow
75+
--> demo.rs:9:9
76+
|
77+
9 | b - a
78+
| ^^^^^
79+
80+
error[E0999]: arithmetic operation may overflow
81+
--> demo.rs:7:9
82+
|
83+
7 | a - b
84+
| ^^^^^
85+
86+
error: aborting due to 2 previous errors
87+
```
88+
89+
You might *fix* the errors, i.e., prove the function have no overflows,
90+
by requiring the *inputs* also be non-negative:
91+
92+
```rust
93+
#[allow(dead_code)]
94+
#[cfg_attr(flux, flux::opts(check_overflow = true))]
95+
#[cfg_attr(flux, flux::spec(fn(a: i32{0 <= a}, b: i32{0 <= b}) -> i32{v: 0 <= v}))]
96+
fn test_abs(a:u32, b:u32) -> u32 {
97+
if a > b {
98+
a - b
99+
} else {
100+
b - a
101+
}
102+
}
103+
```
104+
105+
This time `flux --crate-type=lib demo.rs` finishes swiftly without reporting any errors.
106+
107+
For a more detailed online interactive tutorial, with many more examples, see [the Flux book](https://flux-rs.github.io/flux).
108+
109+
## Using Flux to verify the (model-checking fork of) the Rust Standard Library
110+
111+
Currrently, we have configured Flux to run on the
112+
[model-checking fork](https://github.com/model-checking/verify-rust-std)
113+
of the Rust Standard Library. You can run Flux on
114+
115+
1. a single function,
116+
2. a single file,
117+
3. a set of files matching a glob-pattern, or
118+
4. the entire crate.
119+
120+
### Running on a Single Function
121+
122+
Suppose the function is in a file inside `library/core/src/`, e.g.,
123+
`library/core/src/ascii/ascii_char.rs`.
124+
For example, let's suppose `test_abs` was added to the end of that file,
125+
*with* the `check_overflow = true` and *without* the `flux::spec` contract.
126+
Then if you did
127+
128+
```bash
129+
$ cd library/core
130+
$ FLUXFLAGS="-Fcheck-def=test_abs" cargo flux
131+
```
132+
133+
you should get some output like
134+
135+
```
136+
Checking core v0.0.0 (/verify-rust-std/library/core)
137+
138+
error[E0999]: arithmetic operation may overflow
139+
--> core/src/ascii/ascii_char.rs:635:9
140+
|
141+
635 | b - a
142+
| ^^^^^
143+
144+
error[E0999]: arithmetic operation may overflow
145+
--> core/src/ascii/ascii_char.rs:633:9
146+
|
147+
633 | a - b
148+
| ^^^^^
149+
150+
error: could not compile `core` (lib) due to 2 previous errors
151+
152+
Checking core v0.0.0 (/verify-rust-std/library/core)
153+
Finished `flux` profile [unoptimized + debuginfo] target(s) in 5.54s
154+
```
155+
156+
157+
You can now fix the error by adding the non-negative input specification above the definition
158+
of `test_abs`
159+
160+
```rust
161+
#[cfg_attr(flux, flux::spec(fn(a: i32{0 <= a}, b: i32{0 <= b}) -> i32{v: 0 <= v})]
162+
```
163+
164+
and when you re-run, it should finish with no warnings
165+
166+
**NOTE** When checking inside `core`, we wrap the `flux` specification attributes
167+
in `#[cfg_attr(flux,...)]` so they are only read by flux.
168+
169+
### Running on a Single File
170+
171+
To run on a single _file_ you can just pass the name of that file to flux (relative from the
172+
crate root) as
173+
174+
```bash
175+
$ cd library/core
176+
$ FLUXFLAGS="-Finclude=src/ascii/ascii_char.rs" cargo flux
177+
```
178+
179+
### Running on a Globset of Files
180+
181+
To run on a comma-separated _globset of files_, e.g., an entire module, you can just pass
182+
the appropriate globset as
183+
184+
```bash
185+
$ cd library/core
186+
$ FLUXFLAGS="-Finclude=src/ascii/*" cargo flux
187+
```
188+
189+
### Configuring Flux via `Cargo.toml`
190+
191+
Flux can also be configured in the `Cargo.toml` under the
192+
`[package.metadata.flux]` section.
193+
194+
You can add or remove things from the `include` declaration there
195+
to check other files. Currently, it is configured to only run on a
196+
tiny subset of the modules; you should comment out that line if you
197+
want to run on _all_ of `core`.
198+
199+
You can run flux on all the parts of the `core` crate specified in `include`
200+
directive in the `Cargo.toml` by doing
201+
202+
```bash
203+
$ cd library/core
204+
$ cargo flux
205+
```
206+
207+
### Running on the Entire Crate
208+
209+
Currently the `core/Cargo.toml` is configured (see the `[package.metadata.flux]`) to
210+
only run on a tiny subset of the modules, you should comment out that line if you
211+
really want to run on _all_ of `core`, and then run
212+
213+
```bash
214+
$ cd library/core
215+
$ cargo flux
216+
```
217+
218+
Sadly, various Rust features exercised by the crate are not currently supported by
219+
Flux making it crash ignominously.
220+
221+
You can tell it to do a "best-effort" analysis by ignoring those crashes
222+
(as much as possible) by
223+
224+
```bash
225+
$ FLUXFLAGS="-Fcatch-bugs" cargo flux
226+
```
227+
228+
in which case Flux will grind over the whole crate and point out nearly 300+ *possible*
229+
warnings about overflows, array bounds accesses etc.,
230+
and also about 200+ ICE (places where it crashes!) To do this, you may also have
231+
to tell Flux to not check certain modules, e.g. by adding
232+
various `flux::trusted` annotations [as shown here](https://github.com/flux-rs/verify-rust-std/blob/fluxable/library/core/src/lib.rs)
233+
234+
235+
## More details
236+
237+
You can find more information on using Flux—especially on how to write different
238+
kinds of specifications and configuration options—in [the Flux book](https://flux-rs.github.io/flux).
239+
Happy proving!

library/core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ check-cfg = [
5151

5252
[package.metadata.flux]
5353
enabled = true
54-
include = [ "src/ascii/*" ]
54+
include = [ "src/ascii{*.rs,/**/*.rs}" ]

0 commit comments

Comments
 (0)