Rustig! - a tool to find your panic!'s

Hello Rustaceans,

(the forum limits the amount of links in a post, please check our readme for all links)

Today I am proud to announce rustig! to you. rustig! is a tool for statical analysis of Rust-generated ELF binaries, specifically to find paths that will lead to panic!.

Getting the tool

The source code is on my company's GitHub.

A little explanation

The following paragraphs are sections from the README.md in the repository.

The name

The name rustig! comes from the Dutch word rustig. Which translates to 'calm down' or equivalent in English. See it as the opposite of 'panic'.

History

The idea for this tool was born while we were working on some code for Cortex-M processors. Using objdump and grep you can easily prove that there is no panic! in the code, because the optimizer has removed those functions from the resulting binary. For non #[no_std] targets the optimizer cannot remove them because the binary is statically linked to the Rust standard libary which contains those functions. We wanted this this tool to be able to prove the abscence of paths to panic! in Rust binaries that contain the standard libary. See the Results section to see why this turned out to be not so easy.

Results

As a test case for this tool some well known crates from the Rust community were used. The results are shown below:

Crate Lines of Code Number of panic paths
Servo 219806 50881
cargo 25892 9439
cargo-make 8243 1195
cargo-edit 671 237

The output of the tool in your terminal is overwhelming considering the numbers of paths shown. To reduce the output the whitelisting option is used. Using whitelisting you can drill down on the results showing only the paths you care about.

Lessons learned

The biggest lesson learned we learned is this: even the smallest piece of Rust software (that uses std) written without calls to unwrap() (or similar) still contains a lot of paths to panic!. Usually this comes from the use of format!(...) (used in println!(...), info!(...) and friends) and from a lot of library functions that do allocation (which can fail).

Who

This tool was written by four students from Delft University doing their Bachelor End Project at Technolution in the Netherlands. The initial idea was provided by Erwin Gribnau who mentored this project on behalf of Technolution. On behalf of Delft University, this project was mentored by Robbert Krebbers.

Their thesis about this project can be found in the repo at Delft University, see the repo for the link.

Erwin Gribnau

37 Likes

This sounds like a neat little tool, particularly for mission-critical applications such as no_std.

Oh wow, you ran this on cargo-edit! Very cool!

How'd you come up with the 671 lines of code, though? According to tokei src/ on the current master (can't find which version you looked at), I get 1635 LOC (2072 total with comments and blanks), with 777 in src/bin/ (the CLI part where panicking is mostly fine), and 858 in the lib part (tokei src/ -e src/bin/), where panics are problematic.

Thanks for developing and releasing this tool! (I was looking for such a tool for some time, and pondered all sorts of solutions to get one done.)

I've played with it for some time today on my Scheme interpreter, and it provided a lot of insights into my code, and especially the code I depend on.


However I think a very important feature is missing: a way to "whitelist" various "usual" panics, such as arithmetic, indexing and unwrapping, since most of these are "accounted" for in the code (or can easily be warned about by clippy). Another especially "usual" panic is memory allocation, and fmt instances.

I've tried the whitelisting configuration file, but didn't identify a good "pattern" to use in order to eliminate the most warnings that fall into the previous listed categories, but at the sametime not be too "broad" as to miss some cases...


On a separate topic, I forked the code on GitHub and made a patch to allow dumping all that analysis in JSON: https://github.com/cipriancraciun/rustig

https://github.com/Technolution/rustig/pull/5

The use-case would be to then use a tool such as jq to filter and process that further.

For example (from the pull request):

./target/release/rustig --json --binary ./target/debug/rustig > /tmp/rustig.json
jq --slurp '
    map(select(.pattern != "unwrap" and .pattern != "arithmetic" and .pattern != "indexing"))
    | map([.pattern, .backtrace[0].procedure.linkage_name_demangled])
    | unique
    | .[]
' < /tmp/rustig.json

Quite interesting! I'm interested in seeing what also might be buildable atop some of the libraries you implemented to enable rustig (panic_analysis and callgraph). Will those libraries be released on crates.io?

Thanks. This tool was indeed written to support writing very robust mission-critical applications. With or without std.

To be honest, I don't know. The students came up with these numbers in their thesis. I'll ask them :slight_smile:.

We have the same experience. Whitelisting can easily push away things you do want to see. I will try to get a hand on the whitelisting configurations we used to create the table in the Readme. Maybe they can be of help.

Thanks! Various output formats was on our to-do list, but the students did not have time to implement them. I will work with you to get your changes merged.

We currently have a blocking issue to release rustig! and the callgraph library to crates.io. We have a dependency on a very specific (non-published) version of capstone. See issue 9.

When this issue is resolved I want to publish both rustig! and the libraries on crates.io.

I was one of these students, so maybe I can explain.

I think the difference can be explained by the fact we excluded test code. We wrote a little script that erased everything after #cfg(test)

1 Like