Skip to content

Commit faa16cb

Browse files
authored
Unrolled build for rust-lang#140903
Rollup merge of rust-lang#140903 - RalfJung:fallback-body-tests, r=WaffleLapkin test intrinsic fallback bodies with Miri `@Urgau` noted in rust-lang#140792 that fallback bodies our backends don't use are untested... which is correct, and it is a problem. So this adds a testing-only flag to Miri to force the use of fallback bodies, and adds a run of the Miri test suite with that flag to CI. This should not take much more than a minute so I hope it's fine? Let's see how long it actually takes. While at it, I made that test run also enable MIR optimizations. Miri's CI has a run with that, and it has caught mir-opt bugs in the past -- this way we'd see the CI failure earlier. r? `@scottmcm`
2 parents 7b84c9e + 6814c38 commit faa16cb

File tree

7 files changed

+46
-11
lines changed

7 files changed

+46
-11
lines changed

src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh

+8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ if [ -z "${PR_CI_JOB:-}" ]; then
4040
else
4141
python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri
4242
fi
43+
# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR
44+
# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug
45+
# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can
46+
# adjust their expectations if needed. This can change the output of the tests so we ignore that,
47+
# we only ensure that all assertions still pass.
48+
MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \
49+
MIRI_SKIP_UI_CHECKS=1 \
50+
python3 "$X_PY" test --stage 2 src/tools/miri -- tests/{pass,panic}
4351
# We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc.
4452
# Also cover some other targets via cross-testing, in particular all tier 1 targets.
4553
case $HOST_TARGET in

src/tools/miri/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ to Miri failing to detect cases of undefined behavior in a program.
393393
disables the randomization of the next thread to be picked, instead fixing a round-robin schedule.
394394
Note however that other aspects of Miri's concurrency behavior are still randomize; use
395395
`-Zmiri-deterministic-concurrency` to disable them all.
396+
* `-Zmiri-force-intrinsic-fallback` forces the use of the "fallback" body for all intrinsics that
397+
have one. This is useful to test the fallback bodies, but should not be used otherwise. It is
398+
**unsound** since the fallback body might not be checking for all UB.
396399
* `-Zmiri-native-lib=<path to a shared object file>` is an experimental flag for providing support
397400
for calling native functions from inside the interpreter via FFI. The flag is supported only on
398401
Unix systems. Functions not provided by that file are still executed via the usual Miri shims.

src/tools/miri/src/bin/miri.rs

+2
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,8 @@ fn main() {
584584
} else if arg == "-Zmiri-ignore-leaks" {
585585
miri_config.ignore_leaks = true;
586586
miri_config.collect_leak_backtraces = false;
587+
} else if arg == "-Zmiri-force-intrinsic-fallback" {
588+
miri_config.force_intrinsic_fallback = true;
587589
} else if arg == "-Zmiri-strict-provenance" {
588590
miri_config.provenance_mode = ProvenanceMode::Strict;
589591
} else if arg == "-Zmiri-permissive-provenance" {

src/tools/miri/src/eval.rs

+3
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ pub struct MiriConfig {
165165
pub address_reuse_cross_thread_rate: f64,
166166
/// Round Robin scheduling with no preemption.
167167
pub fixed_scheduling: bool,
168+
/// Always prefer the intrinsic fallback body over the native Miri implementation.
169+
pub force_intrinsic_fallback: bool,
168170
}
169171

170172
impl Default for MiriConfig {
@@ -203,6 +205,7 @@ impl Default for MiriConfig {
203205
address_reuse_rate: 0.5,
204206
address_reuse_cross_thread_rate: 0.1,
205207
fixed_scheduling: false,
208+
force_intrinsic_fallback: false,
206209
}
207210
}
208211
}

src/tools/miri/src/intrinsics/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2828
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
2929
let this = self.eval_context_mut();
3030

31+
// Force use of fallback body, if available.
32+
if this.machine.force_intrinsic_fallback
33+
&& !this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden
34+
{
35+
return interp_ok(Some(ty::Instance {
36+
def: ty::InstanceKind::Item(instance.def_id()),
37+
args: instance.args,
38+
}));
39+
}
40+
3141
// See if the core engine can handle this intrinsic.
3242
if this.eval_intrinsic(instance, args, dest, ret)? {
3343
return interp_ok(None);

src/tools/miri/src/machine.rs

+5
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,9 @@ pub struct MiriMachine<'tcx> {
614614

615615
/// Cache for `mangle_internal_symbol`.
616616
pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>,
617+
618+
/// Always prefer the intrinsic fallback body over the native Miri implementation.
619+
pub force_intrinsic_fallback: bool,
617620
}
618621

619622
impl<'tcx> MiriMachine<'tcx> {
@@ -770,6 +773,7 @@ impl<'tcx> MiriMachine<'tcx> {
770773
reject_in_isolation_warned: Default::default(),
771774
int2ptr_warned: Default::default(),
772775
mangle_internal_symbol_cache: Default::default(),
776+
force_intrinsic_fallback: config.force_intrinsic_fallback,
773777
}
774778
}
775779

@@ -946,6 +950,7 @@ impl VisitProvenance for MiriMachine<'_> {
946950
reject_in_isolation_warned: _,
947951
int2ptr_warned: _,
948952
mangle_internal_symbol_cache: _,
953+
force_intrinsic_fallback: _,
949954
} = self;
950955

951956
threads.visit_provenance(visit);

src/tools/miri/tests/pass/intrinsics/intrinsics.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,24 @@ fn main() {
3333
assert_eq!(intrinsics::likely(false), false);
3434
assert_eq!(intrinsics::unlikely(true), true);
3535

36-
let mut saw_true = false;
37-
let mut saw_false = false;
36+
// Skip this test when we use the fallback bodies, as that one is deterministic.
37+
// (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.)
38+
if !cfg!(force_intrinsic_fallback) {
39+
let mut saw_true = false;
40+
let mut saw_false = false;
3841

39-
for _ in 0..50 {
40-
if intrinsics::is_val_statically_known(0) {
41-
saw_true = true;
42-
} else {
43-
saw_false = true;
42+
for _ in 0..50 {
43+
if intrinsics::is_val_statically_known(0) {
44+
saw_true = true;
45+
} else {
46+
saw_false = true;
47+
}
4448
}
49+
assert!(
50+
saw_true && saw_false,
51+
"`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
52+
);
4553
}
46-
assert!(
47-
saw_true && saw_false,
48-
"`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
49-
);
5054

5155
intrinsics::forget(Bomb);
5256

0 commit comments

Comments
 (0)