miri: added support for MIRI#4055
Open
dcalavrezo-qorix wants to merge 3 commits into
Open
Conversation
### 1. New public rules
The following rules are now exported from `@rules_rust//rust:defs.bzl`:
- `miri_test`
- `miri_binary`
These are currently **wrapper rules** around already-declared Rust targets.
Example:
```bzl
load("@rules_rust//rust:defs.bzl", "rust_test", "miri_test")
rust_test(
name = "tests",
crate = "my_lib",
)
miri_test(
name = "tests_miri",
crate = ":tests",
)
This first version intentionally wraps existing Rust targets instead of re-exposing the full rust_test / rust_binary attribute
surface.
### 2. New Miri toolchain type
A new toolchain type is introduced:
- @rules_rust//rust:miri_toolchain_type
This is separate from the normal Rust toolchain because Miri requires a different runtime contract:
- bin/miri
- a prebuilt Miri sysroot
- the runtime files needed to execute the Miri driver inside Bazel runfiles/sandbox
### 3. Miri-specific rebuild mode for target-side crates
A new internal build setting / transition enables a Miri-specific compilation mode for target-side Rust crates.
When enabled:
- target-side crates are rebuilt with the Miri sysroot
- target-side crates are compiled with:
- -Zalways-encode-mir
Host-side units are not rebuilt in Miri mode:
- build scripts remain native
- proc-macro crates remain native
- other exec-configuration helpers remain native
This split is required for real projects to work correctly under Miri.
### 4. Direct miri launchers
miri_test and miri_binary generate Bazel launchers that invoke the direct miri driver with a rustc-shaped command line:
- --sysroot=...
- --crate-name=...
- --crate-type=...
- --edition=...
- --target=...
- --extern=...
- -Ldependency=...
For miri_test, the generated launcher also forwards libtest-style filtering and runs with:
- --test
- --test-threads=1
## Why This Is Structured as a Separate Toolchain
Miri is not just another flag on the normal Rust toolchain.
The normal Rust toolchain defines:
- rustc
- normal std/sysroot
- normal compile-time/runtime inputs
The Miri toolchain defines:
- miri
- a Miri-specific sysroot
- Miri runtime files
Keeping these as separate toolchain types makes the model explicit and keeps normal Rust builds unchanged for users who do not use
Miri.
## How Consuming Repos Use It
Consuming repos need two things:
1. a normal Rust toolchain
2. a registered Miri toolchain
In our S-CORE ecosyste, the Miri toolchain is provided by score_toolchains_rust.
### 1. Register the Rust and Miri toolchains
Example .bazelrc configuration:
build:per-x86_64-linux --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu
build:per-x86_64-linux --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu_miri
The first toolchain is the normal Ferrocene Rust toolchain.
The second toolchain provides:
- miri
- the prebuilt Miri sysroot
- runtime files required by the Miri launcher
### 2. Wrap existing Rust targets
#### Tests
load("@rules_rust//rust:defs.bzl", "rust_test", "miri_test")
rust_test(
name = "tests",
crate = "my_lib",
)
miri_test(
name = "tests_miri",
crate = ":tests",
tags = ["manual"],
)
#### Binaries
load("@rules_rust//rust:defs.bzl", "rust_binary", "miri_binary")
rust_binary(
name = "app",
srcs = ["src/main.rs"],
)
miri_binary(
name = "app_miri",
crate = ":app",
tags = ["manual"],
)
### 3. Run them with Bazel
bazel test --config=per-x86_64-linux //path/to:tests_miri
bazel run --config=per-x86_64-linux //path/to:app_miri
## Rule Parameters
### miri_test
Current useful parameters:
- crate
- existing Rust target to execute under Miri
- typically wrap a rust_test(...)
- miri_flags
- flags passed directly to the miri driver
- defaults to:
- -Zmiri-disable-isolation
- miri_args
- arguments forwarded after --
- for tests, this is useful for libtest filtering
- env
- extra runtime environment variables
- env_inherit
- runtime environment variables inherited from the outer environment
- platform
- optional platform override for the wrapped target before Miri-mode rebuild
Example with a test filter:
miri_test(
name = "tests_miri_json_backend",
crate = ":tests",
miri_args = ["json_backend::"],
tags = ["manual"],
)
### miri_binary
Current useful parameters are the same as miri_test, except it wraps a rust_binary-like target and executes it under Miri.
## Current Limitations
This PR is intentionally scoped as a first version.
### 1. Not full rust_test / rust_binary parity
These rules do not yet expose the entire attribute surface of rust_test() or rust_binary().
They currently wrap existing Rust targets instead.
### 2. Pure-Rust graphs only
The current direct-driver implementation rejects targets with native linker inputs.
That means this version supports:
- pure-Rust test targets
- pure-Rust binaries
but not targets that pull in native link artifacts such as:
- cc_library
- other non-Rust linker inputs
### 3. Requires a registered Miri toolchain
If miri_test or miri_binary is used without registering a Miri toolchain, analysis fails with a clear error.
## Validation
This implementation was validated end-to-end against a real consumer repo (persistency) using a Ferrocene-backed Miri toolchain
from score_toolchains_rust.
Validated flow:
- wrap an existing rust_test(...) target with miri_test(...)
- run it with Bazel
- execute the full rust_kvs test harness under Miri
Result:
- all non-ignored tests passed under Miri
- the sharded Miri suite also passed
Signed-off-by: Dan Calavrezo <195309321+dcalavrezo-qorix@users.noreply.github.com>
Added comments into the code for better understanding Signed-off-by: Dan Calavrezo <195309321+dcalavrezo-qorix@users.noreply.github.com>
- stage native linker inputs and C++ runtime libs in Miri runfiles - allow miri_test and miri_binary to inspect the C++ toolchain - reuse rustc native library selection helpers for PIC/runtime handling - export RULES_RUST_MIRI from the launcher for runtime-specific workarounds - fix Bazel test runfiles initialization for the Miri launcher Signed-off-by: Dan Calavrezo <195309321+dcalavrezo-qorix@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds first-class Miri support to
rules_rustthrough two new public rules:miri_testmiri_binaryThe implementation uses the direct
miridriver, notcargo miri.That means Bazel remains in control of the crate graph and action inputs, while Miri is only used for the final interpreted
execution step.
What This PR Adds
1. New public rules
The following rules are now exported from
@rules_rust//rust:defs.bzl:miri_testmiri_binaryThese are currently wrapper rules around already-declared Rust targets.
Example:
This first version intentionally wraps existing Rust targets instead of re-exposing the full rust_test / rust_binary attribute
surface.
2. New Miri toolchain type
A new toolchain type is introduced:
This is separate from the normal Rust toolchain because Miri requires a different runtime contract:
3. Miri-specific rebuild mode for target-side crates
A new internal build setting / transition enables a Miri-specific compilation mode for target-side Rust crates.
When enabled:
Host-side units are not rebuilt in Miri mode:
This split is required for real projects to work correctly under Miri.
4. Direct miri launchers
miri_test and miri_binary generate Bazel launchers that invoke the direct miri driver with a rustc-shaped command line:
For miri_test, the generated launcher also forwards libtest-style filtering and runs with:
Why This Is Structured as a Separate Toolchain
Miri is not just another flag on the normal Rust toolchain.
The normal Rust toolchain defines:
The Miri toolchain defines:
Keeping these as separate toolchain types makes the model explicit and keeps normal Rust builds unchanged for users who do not use
Miri.
How Consuming Repos Use It
Consuming repos need two things:
In our S-CORE ecosyste, the Miri toolchain is provided by score_toolchains_rust.
1. Register the Rust and Miri toolchains
Example .bazelrc configuration:
build:per-x86_64-linux --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu
build:per-x86_64-linux --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu_miri
The first toolchain is the normal Ferrocene Rust toolchain.
The second toolchain provides:
2. Wrap existing Rust targets
Tests
load("@rules_rust//rust:defs.bzl", "rust_test", "miri_test")
rust_test(
name = "tests",
crate = "my_lib",
)
miri_test(
name = "tests_miri",
crate = ":tests",
tags = ["manual"],
)
Binaries
load("@rules_rust//rust:defs.bzl", "rust_binary", "miri_binary")
rust_binary(
name = "app",
srcs = ["src/main.rs"],
)
miri_binary(
name = "app_miri",
crate = ":app",
tags = ["manual"],
)
3. Run them with Bazel
bazel test --config=per-x86_64-linux //path/to:tests_miri
bazel run --config=per-x86_64-linux //path/to:app_miri
Rule Parameters
miri_test
Current useful parameters:
Example with a test filter:
miri_test(
name = "tests_miri_json_backend",
crate = ":tests",
miri_args = ["json_backend::"],
tags = ["manual"],
)
miri_binary
Current useful parameters are the same as miri_test, except it wraps a rust_binary-like target and executes it under Miri.
Current Limitations
This PR is intentionally scoped as a first version.
1. Not full rust_test / rust_binary parity
These rules do not yet expose the entire attribute surface of rust_test() or rust_binary().
They currently wrap existing Rust targets instead.
2. Pure-Rust graphs only
The current direct-driver implementation rejects targets with native linker inputs.
That means this version supports:
but not targets that pull in native link artifacts such as:
3. Requires a registered Miri toolchain
If miri_test or miri_binary is used without registering a Miri toolchain, analysis fails with a clear error.
Validation
This implementation was validated end-to-end against a real consumer repo (persistency) using a Ferrocene-backed Miri toolchain
from score_toolchains_rust.
Validated flow:
Result: