This is a static simulator for Rust programs. It runs a set of test cases and attempts to prove that all assertions pass on all valid inputs.
See our 2-minute demo video for an example of crux-mir
's basic
functionality.
crux-mir
uses several submodules, so make sure they're initialized:
$ git submodule update --init
Next, navigate to the crucible/dependencies/mir-json
directory and install
mir-json
according to the instructions in the mir-json
README.
Use GHC 9.4, 9.6, or 9.8. From the crux-mir
directory, run:
$ cabal v2-install exe:crux-mir --overwrite-policy=always
Then translate the Rust libraries in lib/
:
$ ./translate_libs.sh
If you want to cross-compile for a different target, you can optionally set the
environment variable TARGET
to a target
triple when
running ./translate_libs.sh
. This is experimental and we have only tested
wasm32-unknown-unknown
to work; you might get build errors for other targets.
$ TARGET=wasm32-unknown-unknown ./translate_libs.sh
When upgrading from a previous version, first install the new mir-json
version, then rerun the cabal v2-install
and ./translate_libs.sh
commands.
crux-mir
looks for functions with the #[crux::test]
attribute and runs them
as tests. You may need to add #![feature(custom_attribute)]
to the crate
root to use the #[crux::test]
attribute. These can both be conditionally
compiled by checking for the crux
configuration predicate using
#[cfg_attr(crux, crux::test)]
.
Test cases can create and manipulate symbolic values using the functions in the
crucible
Rust crate. See
example/ffs/lib.rs
or the files in
test/symb_eval/
for examples of creating symbolic values
and asserting properties about them.
Set the CRUX_RUST_LIBRARY_PATH
environment variable to the path to the
translated libraries:
$ export CRUX_RUST_LIBRARY_PATH=.../crux-mir/rlibs
In the directory of a Cargo project (such as the find-first-set example), run the project's symbolic tests:
$ cargo crux-test
cargo-crux-test
(part of mir-json
) will translate the code to MIR, then
invoke crux-mir
to symbolically simulate the test cases.
To compile and test a single Rust program:
$ cabal v2-exec -- crux-mir test/conc_eval/prim/add1.rs
(Should print 2.)
The example/ffs/ directory in this repository contains a simple
library with concrete and symbolic tests. Use cargo crux-test
to run the
symbolic test, which proves that an optimized find-first-set function is
equivalent to a simple reference implementation.
A fork of the curve25519-dalek library with symbolic tests for the Scalar52
type is available here. This is the code that appears in the
crux-mir
demo video.
To run crux-mir
's test suite:
$ cabal v2-test
You need to have built and installed the mir-json tool such that it
can be found on your $PATH.
You also need translated libraries for the Rust target architecture
you're testing on.
Make sure that the rlibs
symlink exists and points to the right
architecture's libraries.
If not, run the translate_libs.sh
script as described above under
Installation.
Some tests are not yet expected to succeed, as crux-mir is still under development. These tests are marked accordingly, so that the entire test suite is still expected to pass.
Files that are not yet expected to work correctly begin with // FAIL:
and
a brief comment describing the reason for the expected failure.
crux-mir
does not support reasoning about certain types of unsafe code. Many
functions in the standard library rely on unsafe code; we have reimplemented
some of these in terms of safe code or custom crux-mir
intrinsics, but many
unsupported functions still remain. Test cases that call into unsupported code
will produce assertion failures with messages like don't know how to call core::intrinsics::transmute
.
Currently, crux-mir
also has trouble supporting references and function
pointers in constant expressions and static initializers.