{"id":13672110,"url":"https://github.com/Technolution/rustig","last_synced_at":"2025-04-27T21:32:02.008Z","repository":{"id":48315295,"uuid":"137888551","full_name":"Technolution/rustig","owner":"Technolution","description":"A tool to detect code paths leading to Rust's panic handler","archived":false,"fork":false,"pushed_at":"2021-08-02T04:14:40.000Z","size":200,"stargazers_count":219,"open_issues_count":21,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-30T14:56:27.522Z","etag":null,"topics":["analysis","dwarf","elf","linux-app","rust-crate","rust-lang","rustlang"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Technolution.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE-2.0","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-19T12:29:07.000Z","updated_at":"2024-08-22T18:31:16.000Z","dependencies_parsed_at":"2022-09-21T11:32:06.543Z","dependency_job_id":null,"html_url":"https://github.com/Technolution/rustig","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Technolution%2Frustig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Technolution%2Frustig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Technolution%2Frustig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Technolution%2Frustig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Technolution","download_url":"https://codeload.github.com/Technolution/rustig/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224087137,"owners_count":17253509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analysis","dwarf","elf","linux-app","rust-crate","rust-lang","rustlang"],"created_at":"2024-08-02T09:01:26.988Z","updated_at":"2024-11-11T10:30:19.848Z","avatar_url":"https://github.com/Technolution.png","language":"Rust","readme":"Rustig!\n================\n\nThis software can be used to check whether your Rust software has any paths leading to the _panic_ handler. \n\nThis tool is intended to be used by developers during coding and on CI systems to continuously check for possible \n_panic_'s.\n\n## Code Status\n\n[![Build Status](https://api.travis-ci.com/Technolution/rustig.svg?branch=master)](https://travis-ci.com/Technolution/rustig)\n\n## The name\nThe name _rustig!_ comes from the Dutch word _rustig_. Which translates to 'calm down' or equivalent in English. \nSee it as the opposite of 'panic'. **Don't panic!**.\n\n## Background\n\nSoftware written in Rust has a panic handler. When the panic handler is called the current thread will be terminated \n(or the process will be exited, determined by rustc's build flag 'panic'). Certain conditions in Rust software trigger \nthis panic handler. Accessing an array out of bounds is an example of such a trigger. \n\nThis tool will analyze the ELF executable, generate a callgraph from the debug info in the executable, and report the \npaths leading from your code to the panic handler. \n\n## History\nThe idea for this tool was born while we were on some code for Cortex-M processors. Using `objdump` and `grep` you can \neasily prove that there is no `panic!` in the code, because the optimizer has removed those functions from the resulting \nbinary. For non `#[no_std]` targets the optimizer cannot remove them because the binary is statically linked to the\nRust standard library which contains those functions. We wanted this tool to be able to prove the abscence\nof paths to `panic!` in Rust binaries that contain the standard library. See the [Results](#Results) section to see \nwhy this turned out to be not so easy. \n\n## Who\nThis tool was written by four students from Delft University doing their _Bachelor End Project_ at \n[Technolution](https://technolution.eu/en/) in the Netherlands. The initial idea was provided by Erwin Gribnau who \nmentored this project on behalf of Technolution. On behalf of Delft University, this project was mentored by \n[Robbert Krebbers](https://robbertkrebbers.nl/). \n\nTheir thesis about this project can be found in the repo at Delft University: \n[link](http://resolver.tudelft.nl/uuid:c4e95618-390d-4210-a76f-ce23640a194d).\n\n## Installing the latest version from source\nYou can use *cargo* to install our binary directly from the sources in the Git-repository:\n```\ncargo install --git https://github.com/Technolution/rustig rustig\n```\n## Using the tool\n\nThe tool accepts various command line flags and options:\n\n### Options\n* `--binary` (`-b`): The path of the binary to analyze, relative to the present working directory. This should be an\nexecutable in [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) format. The executable should be \ncompiled for x86 or x86_64 architectures, with debug information enabled.\n\n* `--config`: Path to a configuration file, relative to the present working directory. Defaults to 'rustig.toml'.\nIf the default file does not exist, no configuration file is used. However, if this argument is passed explicitly, but \nthe file does not exist, the tool will exit with an error. Currently, this file is only used for whitelisting, which is \nexplained in the section on [whitelisting](#whitelisting).\n\n* `--crates` (`-c`): Option to mark crates as analysis target (more on analysis target in the \n[how it works](#how-it-works) section). By default, the crate in which the `main` function is defined is used as \nanalysis target.\n\n* `--callgraph` (`-g`): Option to dump the callgraph in [dot](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) \nformat. It takes one or more of 2 values:\n    * `full`: Writes the full call graph, without metadata, to 'rdp-callgraph-{projectname}-full.dot'\n    * `filtered`: Writes the call graph containing only the nodes that lead to a panic, with metadata, to \n    'rdp-callgraph-{projectname}-filtered.dot'\n\n### Flags\n* `--full-crate-analysis` (`-f`): Analyses all functions in the analysis target, instead of only the main function. \n  (More about this flag in the in the section on [whitelisting](#whitelisting)).\n* `--silent` (`-s`): Print no output to stdout.\n* `--verbose` (`-v`): Print detailed panic traces to stdout.\n\n### Exit codes\n* 0: No errors during execution, and no _panic_ traces found.\n* 1: No errors during execution, but _panic_ traces were found.\n* 101: Internal error during execution.\n\n## How it works\n\nInternally, the tool builds a call graph from the binary. (This call graph can be dumped with the `--callgraph` \nflag). After that the tool wil print all calls from a function in the same crate as the main function (or the crates given by the \n`--crates` flag) to a function outside this crate that might lead to a _panic!_.\n\n## Whitelisting\n\nIt is possible to whitelist functions. When a function is whitelisted, traces that would contain that function are \nignored.\n\nWhitelisting can be done in the configuration file. An example, to whitelist formatting, could be:\n```text\nwhitelisted_functions = [\n  {\n    function_name = \"fmt::format\",\n    crate_name = \"stdlib\",\n    crate_version=\"1.26.2\",\n    strict = true\n  }\n]\n```\n\nThe whitelisted functions are defined in an array with key `whitelisted_functions`. The objects in the array contain \nthe following fields:\n* `function_name` (required): The name of the function to whitelist. This name may be prepended with an arbitrary \n  number of namespaces. However, partial namespaces are not accepted. For example, if a function has name \n  `core::fmt::format`, the names `format`, `fmt::format` and `core::fmt::format` would match, but `ormat` or \n  `mt::format` would not.\n* `crate_name`: (required) The name of the crate the function is defined in. When executing the tool, this is usually \n  printed between brackets in the output.\n* `crate_version`: (optional) The version of the crate the function is defined in. If another version of the crate is \n  detected, the function will not be whitelisted.\n* `strict`: (optional) If `true`, crates for which the name matches, but the version could not be determined, are not \n  matched. If `false`, the crate will be matched. The default is `false`.\n\n### Full crate analysis\n\nNormally, when function `foo` is whitelisted, only traces through functions that are called via `foo` *only* will be \nignored. This behaviour can be disabled by setting the `--full-crate-analysis` flag.\n\nFor example, for the following function trace: \n`crate::main` -\u003e `crate::whitelisted_function` -\u003e `crate::foo` -\u003e `std::panic::panic` no trace would be reported by \ndefault. When the `--full-crate-analysis` flag is set, a trace (`crate::foo` -\u003e `std::panic::panic`) would be reported.\n\n\n## Limitations\nFor dynamic invocations this tool makes assumptions. The assumption made is that when the address of a trait \nimplementation is loaded using the Load Effective Address call, all functions in that trait are considered used. All \npaths leading to panic! from one of those functions (whether actually used or not) will be reported. \n\nCurrently, the tool is only able to build callgraphs for x86_64 ELF binaries. The reason for this limitation is that\nbuilding the callgraph requires reading the assembly and finding jump/call instructions (like `callq` and `lea`). This \nalgorithm is currently only implemented for x86 instruction sets. \n\n\n## Results\n\nAs a test case for this tool some well-known crates from the Rust community were used. The results are shown below:\n\n| Crate      | Lines of Code | Number of panic paths |\n|------------|--------------:|----------------------:|\n| Servo      |        219806 |                 50881 |\n| cargo      |         25892 |                  9439 |\n| cargo-make |          8243 |                  1195 |\n| cargo-edit |           671 |                   237 |\n\nThe output of the tool in your terminal is overwhelming considering the numbers of paths shown. To reduce the output\nthe whitelisting option is used. Using whitelisting you can drill down on the results showing only the paths you care \nabout.\n\nAgain, for some well-known crates this is performed, the results are shown below:\n\nIn this table, the column **Total** denotes all the panic traces in the program. \nIn the column **Project specific**, we whitelisted some functions that were explicitly\nmeant to panic if something went wrong in the setup or teardown phase. In the subsequent columns\n**Format**, **Allocation** and **Indexing**, we disabled traces for string formatting, memory allocation and\narray indexing respectively. We whitelisted these because, based on our experience, they are very\nunlikely to panic . These whitelists are added on top of the project-specific whitelists. In the **All** column,\nwe combined all of these whitelisting configurations. The traces in this output did not have a cause that was \neasiy to identify, and would require more investigation. In the last two columns, we identified how many\nof the traces in the **All** column were caused by an unwrap or by use of the panic macro itself.\n\n| Crate        | Total | Project specific | Format | Allocation| Indexing | All | Unwrap | Direct |\n|--------------|------:|-----------------:|-------:|----------:|---------:|----:|-------:|-------:|\n|cargo         |  9439 |             7782 |4833 |5514 |6758 |2238 |738 |49\n|cargo-make    |  1195 |             1136 |695 |697 |1030 |148 |71 |8\n|cargo-add     |   388 |              283 |201 |209 |236 |95 |17 |4\n|cargo-rm      |   126 |              108 |64 |91 |97 |37 |5 |0\n|cargo-upgrade |   415 |              298 |204 |231 |267 |112 |16 |2\n\nBased on these results, we tried to estimate the impact of this output. It turned out that many panics\nwere difficult to trigger, since they are very environment-specific. However, in the cargo-make project,\nwe were able to trigger two panics after trying for just half an hour. One panic occures when you remove\nthe read permissions for the current user on input files for cargo-make. The other panic occures when such\nan input file is not formatted correctly. This demonstrates it is possible to find bugs with the tool; \nhowever, it certainly requires some effort. We would like to point out, that this particalur bug is not\na serious problem for a command-line program. But, when bugs like these can be triggered on applications\nconnected to the Internet, you can execute a denial-of-service attack against such an application. \n\n## License\nMIT or APACHE-2.0 (see the LICENSE files in the repository).\n\n## Developer notes\nTo test this tool a series of binaries is generated (in test_subjects and test_subjects_stable_rustc). \nThe binaries in the latter directory are generated using a specific version of the Rust compiler. \nSee build.rs in test_common for details. \n\n### Warning for RLS users\nIf you use the Rust Language Server (i.e. Visual Studio Code with Rust plugin), the generated binary \nis overwritten by a version compiled with the default compiler settings. This will cause some tests to fail!\n\nThe tests that are known to fail in that case are:\n`parse::test::test_example_binary_debug_abbrev` and `callgraph::test::test_call_graph_creation`.\n","funding_links":[],"categories":["Rust"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTechnolution%2Frustig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTechnolution%2Frustig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTechnolution%2Frustig/lists"}