contact: use my ETH email address
[web.git] / personal / _posts / 2020-09-28-miri.md
1 ---
2 title: "What (not so) recently happened in Miri"
3 categories: rust
4 reddit: /rust/comments/j1fxd3/what_not_so_recently_happened_in_miri/
5 ---
6
7 A lot has happened in Miri over the last year and a half, and I figured it would be a good idea to advertise all this progress a bit more widely, so here we go.
8 We also recently performed a breaking change that affects some CI configurations, so this post serves as an announcement for you to update your CI configuration if needed.
9
10 For the uninitiated, [Miri](https://github.com/rust-lang/miri/) is an interpreter that runs your Rust code and checks if it triggers any [Undefined Behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html).
11 You can think of it a as very thorough (and very slow) version of valgrind: Miri will detect when your program uses uninitialized memory incorrectly, performs out-of-bounds memory accesses or pointer arithmetic, violates key language invariants, does not ensure proper pointer alignment, or causes incorrect aliasing.
12 As such, it is most helpful when writing unsafe code, as it aids in ensuring that you follow all the rules required for unsafe code to be correct and safe.
13 Miri also detects memory leaks, i.e., it informs you at the end of program execution if there is any memory that was not deallocated properly.
14
15 <!-- MORE -->
16
17 However, being an interpreter, Miri is limited in the kinds of code it can execute -- everything that would usually involve interacting with C libraries or the operating system needs to be specifically supported, as C code cannot be interpreted by Miri.
18 Miri also lacks support for some Rust features that are hard to interpret, but we are slowly closing these gaps.
19
20 ## Recent and past progress in Miri
21
22 During the last 1.5 years, thanks to a series of excellent contributors, we made a lot of progress towards supporting more and more Rust code to run in Miri.
23 I am going to list some highlights below.
24
25 If you want to learn how to use Miri yourself, scroll down to the end of this post.
26 If you are using Miri already, maybe you are still passing flags like `--exclude-should-panic` or disabling tests that require concurrency; you should be able to update those flags now.
27 Also note the breaking change in how `cargo miri` interprets CLI arguments below!
28
29 ### Randomness and `HashMap`
30
31 The Rust `HashMap` picks a new random seed for each execution.
32 This seed in obtained from the operating system, an operation which Miri did not support until @Aaron1011 implemented `getrandom` ([#683](https://github.com/rust-lang/miri/pull/683)).
33 To ensure the same programs behaves the same way each time it is run by Miri, Miri internally uses a deterministic RNG (seeded with `0`, but that can be changed via `-Zmiri-seed`) to implement getrandom.
34 This PR also enabled Miri to be used with projects that use the `rand` crate for randomness.
35
36 However, this also means randomness in Miri is actually not random, so *do not use Miri to perform any important cryptographic operations*.
37
38 ### Unwinding
39
40 Miri used to just abort program execution in case of a panic.
41 To better match the behavior of real Rust programs, @Aaron1011 implement proper unwinding support in Miri ([#693](https://github.com/rust-lang/miri/pull/693)).
42 He even implemented catching panics again, which required aligning quite a few pieces across rustc, the standard library, and Miri itself.
43 This means Miri can finally also execute `#[should_panic]` tests.
44 Since recently, this is supported even for Windows targets.
45
46 ### Pointer-integer casts
47
48 Thanks to @christianpoveda, Miri now properly supports casting arbitrary pointers to integers and back ([#779](https://github.com/rust-lang/miri/pull/779)).
49
50 Recently, I also adjusted the alignment check to fully take this information into account, so that Miri can now run code that performs its own alignment logic ([#1513](https://github.com/rust-lang/miri/pull/1513)).
51 Notice however that this can lead to code that just happens to work by pure chance; to properly test such code, the test should be run at least 10 times.
52
53 ### File system access
54
55 @christianpoveda went on to implement file system access (this series of PRs started with [#962](https://github.com/rust-lang/miri/pull/962)).
56 Later, @divergentdave improved that support with directory listing and some related operations (starting with [#1152](https://github.com/rust-lang/miri/pull/1152)).
57 This means programs running in Miri can now read from and write to files on the host computer.
58 This is the first form of communication that we support between the interpreted program and the outside world.
59 Communication needs to be explicitly requested via `-Zmiri-disable-isolation`; by default, Miri isolates the program to ensure that each execution is perfectly reproducible.
60
61 File system access is only supported on Linux and macOS targets, but due to cross-interpretation this is not a problem even for Windows users -- see the next point.
62
63 ### Cross-interpretation
64
65 Based on earlier work by @Aaron1011 who made Miri use check-only builds both for the standard library and the interpreted crate itself ([#1136](https://github.com/rust-lang/miri/pull/1136)),
66 I made Miri support "cross-interpretation" ([#1249](https://github.com/rust-lang/miri/pull/1249)).
67 This means even when you are on a Windows host, you can pass `--target x86_64-unknown-linux-gnu` so Miri will interpret the program *as if* it was running on Linux, in particular using all the Linux parts of the standard library for the interaction with the operating system.
68 Sine Miri supports the Linux APIs for file system access, it can interpret these programs even when running on a Windows host.
69
70 This is particularly useful when testing target features that differ from the host platform: for example, even on a 64bit macOS host, you can run programs for the 32bit Linux target (`--target i686-unknown-linux-gnu`), making sure your logic works for different pointer sizes.
71 Miri also supports big-endian targets like `--target mips64-unknown-linux-gnuabi64`, so if your code is endianess-sensitive, you can test if it behaves correctly on big-endian systems.
72 And finally cross-interpretation was enormously helpful for developing Miri itself; for example, I relied on this when fixing up our panic and unwinding support for Windows targets.
73
74 ### Concurrency
75
76 Earlier this year, @vakaras surprised me by suddenly showing up with a series of patches that equip Miri with support for concurrency ([#1284](https://github.com/rust-lang/miri/pull/1284)).
77 This is work he did during an internship with Amazon, so also thank you to Amazon for sponsoring this work!
78 Now Miri programs can spawn threads and interact via locks or atomics.
79 There are some caveats though: Miri does not detect data races, so programs with incorrect synchronization can cause Undefined Behavior through data races without Miri noticing.
80 Also Miri's scheduler is rather crude, so programs can be stuck in infinite loops under some circumstances.
81
82 ### Better `cargo` compatibility (breaking change!)
83
84 Recently, I mostly re-wrote the main entry point for users to execute programs in Miri, `cargo miri` ([#1540](https://github.com/rust-lang/miri/pull/1540)).
85 It is now more compatible with cargo itself: `cargo test` and `cargo miri test` support the exact same flags, and likewise for `cargo run` and `cargo miri run`.
86
87 However, this required a breaking change: previously, the way to pass flags to Miri itself and the program when executing the test suite was `cargo miri test -- <miri flags> -- <test suite flags>`.
88 Now flags are passed via `cargo miri test -- <test suite flags>` like they are with `cargo test`; if you need to pass flags to Miri, you can set the `MIRIFLAGS` variable which works like `RUSTFLAGS`.
89 I also removed support for `cargo miri` without further arguments, which used to be an alias for `cargo miri run`.
90 The reason is that (a) `cargo miri test` is actually used much more frequently and (b) disambiguating these options while also supporting arbitrary flags is tricky.
91
92 If you have set up your CI to run tests in Miri, please make sure to adjust your configuration to the new format.
93 For now, Miri still supports the old style (and emits an appropriate warning), but the intention is to remove that support code eventually.
94 If your project is hosted on GitHub and is affected by the change, you should have already received a notification from me, but I might have missed some projects and of course not everything is on GitHub.
95 While at it, you can also remove `cargo miri setup` from your CI script; that is no longer needed as thanks to @dtolnay Miri automatically detects when it runs on CI and goes into non-interactive mode.
96
97 ### ... and more
98
99 This list is by far not exhaustive.
100 Many small functions, from trigonometry to environment variable access to timekeeping, have been implemented over the last months, ever growing the range of programs that Miri can execute.
101 Thank you to @Aaron1011, @christianpoveda, @divergentdave, @JOE1994, and @samrat!
102 I hope I did not miss anyone...
103
104 ## Using Miri
105
106 If this post made you curious and you want to give Miri a try, here's how to do that.
107 Assuming you have a crate with some unsafe code, and you already have a test suite (you are testing your unsafe code, right?), you can just install Miri (`rustup +nightly component add miri`) and then run `cargo +nightly miri test` to execute all tests in Miri (except for doctests, which are not supported yet).
108 Note that this requires the nightly toolchain as Miri is still an experimental tool.
109
110 Miri is very slow, so it is likely that some tests will take way too long to be feasible.
111 You can adjust iteration counts in Miri without affecting non-Miri testing as follows:
112 {% highlight rust %}
113 let limit = if cfg!(miri) { 10 } else { 10_000 };
114 {% endhighlight %}
115 If your test suite needs to access OS facilities such as timers or the file system, set `MIRIFLAGS=-Zmiri-disable-isolation` to enable those.
116 (Miri will tell you when that is necessary.)
117 If your test suite runs into an unsupported operation, please [report an issue](https://github.com/rust-lang/miri/issues).
118
119 If you want to add Miri to your CI to ensure your test suite keeps working in Miri, please consult our [README](https://github.com/rust-lang/miri/#running-miri-on-ci).
120 That document is also a great starting point for any other questions you might have.
121
122 Miri is also integrated into the [Rust Playground](https://play.rust-lang.org/): you can select Miri in the "Tools" menu to check the code for Undefined Behavior.
123
124 If Miri complains about your code and you do not understand why, I am happy to help!
125 The best places to ask probably are Zulip (the #general stream seems fine), and the Miri issue tracker.
126 Asking publicly is strongly encouraged so other people can help answer the question, and everyone can learn from the responses.
127 Questions are much easier to answer if you manage to reproduce the problem in a small self-contained bit of example code (ideally on the playground), but feel free to ask even if you do not know how to reduce the problem.
128
129 ## Helping Miri
130
131 If you want to help improve Miri, that's awesome!
132 The [issue tracker](https://github.com/rust-lang/miri/issues) is a good place to start; the list of issues is short enough that you can just browse through it rather quickly to see if anything pikes your interest.
133 Another good starting point is to try to implement the missing bit of functionality that keeps your test suite from working.
134 If you need any mentoring, just get in touch. :)
135
136 That's it for now.
137 I am totally blown away by how many people are already using Miri; this endeavor of re-shaping the way we approach correctness of unsafe code has been way more successful than I expected.
138 I hope Miri can also help you to ensure correctness of your unsafe code, and I am excited for what the next year of Miri development will bring. :D