Skip to content

Commit efca4e9

Browse files
committed
Tutorial revisions in response to customer feedback (rust-lang#490)
1 parent eb2a366 commit efca4e9

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

rmc-docs/src/tutorial-first-steps.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ VERIFICATION FAILED
5353
RMC has immediately found a failure.
5454
Notably, we haven't had to write explicit assertions in our "proof harness": by default, RMC will find a host of erroneous conditions which include a reachable call to `panic` or a failing `assert`.
5555

56+
### Getting a trace
57+
5658
By default, RMC only reports failures, not how the failure happened.
5759
This is because, in its full generality, understanding how a failure happened requires exploring a full (potentially large) execution trace.
5860
Here, we've just got some nondeterministic inputs up front, but that's something of a special case that has a "simpler" explanation (just the choice of nondeterministic input).

rmc-docs/src/tutorial-kinds-of-failure.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Consider trying a few more small exercises with this example:
6868

6969
1. Exercise: Switch back to the normal/safe indexing operation and re-try RMC. What changes compared to the unsafe operation and why?
7070
(Try predicting the answer, then seeing if you got it right.)
71-
2. Exercise: Remember how to get a trace from RMC? Find out what inputs it failed on.
71+
2. Exercise: [Remember how to get a trace from RMC?](./tutorial-first-steps.md#getting-a-trace) Find out what inputs it failed on.
7272
3. Exercise: Fix the error, run RMC, and see a successful verification.
7373
4. Exercise: Try switching back to the unsafe code (now with the error fixed) and re-run RMC. It should still successfully verify.
7474

@@ -90,6 +90,52 @@ This pattern (two checks for similar issues in safe Rust code) is common, and we
9090

9191
</details>
9292

93+
<details>
94+
<summary>Click to see explanation for exercise 2</summary>
95+
96+
Having run `rmc --visualize` and clicked on one of the failures to see a trace, there are three things to immediately notice:
97+
98+
1. This trace is huge. The standard library `Vec` is involved, there's a lot going on.
99+
2. The top of the trace file contains some "trace navigation tips" that might be helpful in navigating the trace.
100+
3. There's a lot of generated code and it's really hard to just read the trace itself.
101+
102+
To navigate this trace to find the information you need, we recommend searching for things you expect to be somewhere in the trace:
103+
104+
1. Search the document for `__nondet` or `variable_of_interest =` such as `size =`.
105+
We can use this to find out what example values lead to a problem.
106+
In this case, where we just have a couple of `__nondet` values in our proof harness, we can learn a lot just by seeing what these are.
107+
In this trace we find (and the values you get may be different):
108+
109+
```
110+
Step 23: Function main, File tests/bounds-check.rs, Line 43
111+
let size: usize = __nondet();
112+
size = 0ul
113+
114+
Step 27: Function main, File tests/bounds-check.rs, Line 45
115+
let index: usize = __nondet();
116+
index = 0ul
117+
118+
Step 36: Function main, File tests/bounds-check.rs, Line 43
119+
let size: usize = __nondet();
120+
size = 2464ul
121+
122+
Step 39: Function main, File tests/bounds-check.rs, Line 45
123+
let index: usize = __nondet();
124+
index = 2463ul
125+
```
126+
127+
Try not to be fooled by the first assignments: we're seeing zero-initialization there.
128+
They get overridden by the later assignments.
129+
You may see different values here, as it depends on the solver's behavior.
130+
131+
2. Try searching for "failure:". This will be near the end of the document.
132+
Now you can try reverse-searching for assignments to the variables involved.
133+
For example, search upwards from the failure for `i =`.
134+
135+
These two techniques should help you find both the nondeterministic inputs, and see what values were involved in the failing assertion.
136+
137+
</details>
138+
93139
## Overflow and math errors
94140

95141
Consider a different variant on the above function:

rmc-docs/src/tutorial/kinds-of-failure/tests/bounds-check.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
// ANCHOR: code
5+
/// Wrap "too-large" indexes back into a valid range for the array
56
fn get_wrapped(i: usize, a: &[u32]) -> u32 {
67
if a.len() == 0 {
78
return 0;

0 commit comments

Comments
 (0)