Skip to content

Commit fe3038f

Browse files
committed
Auto merge of #118284 - RalfJung:miri, r=RalfJung
Miri subtree update
2 parents 3166210 + 547598b commit fe3038f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+716
-454
lines changed

src/tools/miri/.github/workflows/ci.yml

-4
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ jobs:
3535
steps:
3636
- uses: actions/checkout@v3
3737

38-
- name: Set the tag GC interval to 1 on linux
39-
if: runner.os == 'Linux'
40-
run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV
41-
4238
# Cache the global cargo directory, but NOT the local `target` directory which
4339
# we cannot reuse anyway when the nightly changes (and it grows quite large
4440
# over time).

src/tools/miri/cargo-miri/src/setup.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::env;
44
use std::ffi::OsStr;
5+
use std::fmt::Write;
56
use std::path::PathBuf;
67
use std::process::{self, Command};
78

@@ -140,12 +141,20 @@ pub fn setup(
140141
// Do the build.
141142
if print_sysroot {
142143
// Be silent.
143-
} else if only_setup {
144-
// We want to be explicit.
145-
eprintln!("Preparing a sysroot for Miri (target: {target})...");
146144
} else {
147-
// We want to be quiet, but still let the user know that something is happening.
148-
eprint!("Preparing a sysroot for Miri (target: {target})... ");
145+
let mut msg = String::new();
146+
write!(msg, "Preparing a sysroot for Miri (target: {target})").unwrap();
147+
if verbose > 0 {
148+
write!(msg, " in {}", sysroot_dir.display()).unwrap();
149+
}
150+
write!(msg, "...").unwrap();
151+
if only_setup {
152+
// We want to be explicit.
153+
eprintln!("{msg}");
154+
} else {
155+
// We want to be quiet, but still let the user know that something is happening.
156+
eprint!("{msg} ");
157+
}
149158
}
150159
SysrootBuilder::new(&sysroot_dir, target)
151160
.build_mode(BuildMode::Check)

src/tools/miri/ci.sh

+22-8
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,23 @@ endgroup
3030

3131
# Test
3232
function run_tests {
33-
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
33+
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
3434
begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
3535
else
3636
begingroup "Testing host architecture"
3737
fi
3838

3939
## ui test suite
40-
./miri test
41-
if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
42-
# Host-only tests: running these on all targets is unlikely to catch more problems and would
40+
# On the host and on Linux, also stress-test the GC.
41+
if [ -z "${MIRI_TEST_TARGET:-}" ] || [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
42+
MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
43+
else
44+
./miri test
45+
fi
46+
47+
# Host-only tests
48+
if [ -z "${MIRI_TEST_TARGET:-}" ]; then
49+
# Running these on all targets is unlikely to catch more problems and would
4350
# cost a lot of CI time.
4451

4552
# Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the
@@ -85,10 +92,11 @@ function run_tests {
8592
}
8693

8794
function run_tests_minimal {
88-
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
95+
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
8996
begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
9097
else
91-
begingroup "Testing MINIMAL host architecture: only testing $@"
98+
echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
99+
exit 1
92100
fi
93101

94102
./miri test -- "$@"
@@ -99,16 +107,22 @@ function run_tests_minimal {
99107
endgroup
100108
}
101109

102-
# host
110+
## Main Testing Logic ##
111+
112+
# Host target.
103113
run_tests
104114

115+
# Extra targets.
116+
# In particular, fully cover all tier 1 targets.
105117
case $HOST_TARGET in
106118
x86_64-unknown-linux-gnu)
107119
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
108120
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
109121
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
110122
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
111-
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc atomic env align
123+
# Some targets are only partially supported.
124+
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
125+
MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
112126
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
113127
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
114128
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm

src/tools/miri/miri-script/src/commands.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl Command {
286286
"This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
287287
);
288288
print!(
289-
"To avoid that, abort now and set the `--rustc-git` flag to an existing rustc checkout. Proceed? [y/N] "
289+
"To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
290290
);
291291
std::io::stdout().flush()?;
292292
let mut answer = String::new();

src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
820f06b21f8373060ff7b515715b8440a6a6c197
1+
3668a8af1b81447c4afa1f82f60d7b94b71a549f

src/tools/miri/src/helpers.rs

+80-57
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ use std::time::Duration;
55

66
use log::trace;
77

8+
use rustc_apfloat::ieee::{Double, Single};
89
use rustc_hir::def::{DefKind, Namespace};
910
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
1011
use rustc_index::IndexVec;
1112
use rustc_middle::mir;
1213
use rustc_middle::ty::{
1314
self,
14-
layout::{IntegerExt as _, LayoutOf, TyAndLayout},
15-
IntTy, Ty, TyCtxt, UintTy,
15+
layout::{LayoutOf, TyAndLayout},
16+
FloatTy, IntTy, Ty, TyCtxt, UintTy,
1617
};
1718
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
18-
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
19+
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
1920
use rustc_target::spec::abi::Abi;
2021

2122
use rand::RngCore;
@@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
565566
/// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
566567
/// if this is not the case.
567568
fn assert_target_os_is_unix(&self, name: &str) {
568-
assert!(
569-
target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
570-
"`{name}` is only available for supported UNIX family targets",
571-
);
569+
assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
570+
}
571+
572+
fn target_os_is_unix(&self) -> bool {
573+
self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
572574
}
573575

574576
/// Get last error variable as a place, lazily allocating thread-local storage for it if
@@ -985,65 +987,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
985987
}
986988
}
987989

988-
/// Converts `f` to integer type `dest_ty` after rounding with mode `round`.
990+
/// Converts `src` from floating point to integer type `dest_ty`
991+
/// after rounding with mode `round`.
989992
/// Returns `None` if `f` is NaN or out of range.
990-
fn float_to_int_checked<F>(
993+
fn float_to_int_checked(
991994
&self,
992-
f: F,
995+
src: &ImmTy<'tcx, Provenance>,
993996
cast_to: TyAndLayout<'tcx>,
994997
round: rustc_apfloat::Round,
995-
) -> Option<ImmTy<'tcx, Provenance>>
996-
where
997-
F: rustc_apfloat::Float + Into<Scalar<Provenance>>,
998-
{
998+
) -> InterpResult<'tcx, Option<ImmTy<'tcx, Provenance>>> {
999999
let this = self.eval_context_ref();
10001000

1001-
let val = match cast_to.ty.kind() {
1002-
// Unsigned
1003-
ty::Uint(t) => {
1004-
let size = Integer::from_uint_ty(this, *t).size();
1005-
let res = f.to_u128_r(size.bits_usize(), round, &mut false);
1006-
if res.status.intersects(
1007-
rustc_apfloat::Status::INVALID_OP
1008-
| rustc_apfloat::Status::OVERFLOW
1009-
| rustc_apfloat::Status::UNDERFLOW,
1010-
) {
1011-
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
1012-
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1013-
return None;
1014-
} else {
1015-
// Floating point value can be represented by the integer type after rounding.
1016-
// The INEXACT flag is ignored on purpose to allow rounding.
1017-
Scalar::from_uint(res.value, size)
1001+
fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
1002+
this: &MiriInterpCx<'_, 'tcx>,
1003+
src: F,
1004+
cast_to: TyAndLayout<'tcx>,
1005+
round: rustc_apfloat::Round,
1006+
) -> (Scalar<Provenance>, rustc_apfloat::Status) {
1007+
let int_size = cast_to.layout.size;
1008+
match cast_to.ty.kind() {
1009+
// Unsigned
1010+
ty::Uint(_) => {
1011+
let res = src.to_u128_r(int_size.bits_usize(), round, &mut false);
1012+
(Scalar::from_uint(res.value, int_size), res.status)
10181013
}
1019-
}
1020-
// Signed
1021-
ty::Int(t) => {
1022-
let size = Integer::from_int_ty(this, *t).size();
1023-
let res = f.to_i128_r(size.bits_usize(), round, &mut false);
1024-
if res.status.intersects(
1025-
rustc_apfloat::Status::INVALID_OP
1026-
| rustc_apfloat::Status::OVERFLOW
1027-
| rustc_apfloat::Status::UNDERFLOW,
1028-
) {
1029-
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
1030-
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1031-
return None;
1032-
} else {
1033-
// Floating point value can be represented by the integer type after rounding.
1034-
// The INEXACT flag is ignored on purpose to allow rounding.
1035-
Scalar::from_int(res.value, size)
1014+
// Signed
1015+
ty::Int(_) => {
1016+
let res = src.to_i128_r(int_size.bits_usize(), round, &mut false);
1017+
(Scalar::from_int(res.value, int_size), res.status)
10361018
}
1019+
// Nothing else
1020+
_ =>
1021+
span_bug!(
1022+
this.cur_span(),
1023+
"attempted float-to-int conversion with non-int output type {}",
1024+
cast_to.ty,
1025+
),
10371026
}
1027+
}
1028+
1029+
let (val, status) = match src.layout.ty.kind() {
1030+
// f32
1031+
ty::Float(FloatTy::F32) =>
1032+
float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
1033+
// f64
1034+
ty::Float(FloatTy::F64) =>
1035+
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
10381036
// Nothing else
10391037
_ =>
10401038
span_bug!(
10411039
this.cur_span(),
1042-
"attempted float-to-int conversion with non-int output type {}",
1043-
cast_to.ty,
1040+
"attempted float-to-int conversion with non-float input type {}",
1041+
src.layout.ty,
10441042
),
10451043
};
1046-
Some(ImmTy::from_scalar(val, cast_to))
1044+
1045+
if status.intersects(
1046+
rustc_apfloat::Status::INVALID_OP
1047+
| rustc_apfloat::Status::OVERFLOW
1048+
| rustc_apfloat::Status::UNDERFLOW,
1049+
) {
1050+
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
1051+
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1052+
Ok(None)
1053+
} else {
1054+
// Floating point value can be represented by the integer type after rounding.
1055+
// The INEXACT flag is ignored on purpose to allow rounding.
1056+
Ok(Some(ImmTy::from_scalar(val, cast_to)))
1057+
}
10471058
}
10481059

10491060
/// Returns an integer type that is twice wide as `ty`
@@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10631074
_ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
10641075
}
10651076
}
1077+
1078+
/// Checks that target feature `target_feature` is enabled.
1079+
///
1080+
/// If not enabled, emits an UB error that states that the feature is
1081+
/// required by `intrinsic`.
1082+
fn expect_target_feature_for_intrinsic(
1083+
&self,
1084+
intrinsic: Symbol,
1085+
target_feature: &str,
1086+
) -> InterpResult<'tcx, ()> {
1087+
let this = self.eval_context_ref();
1088+
if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
1089+
throw_ub_format!(
1090+
"attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
1091+
);
1092+
}
1093+
Ok(())
1094+
}
10661095
}
10671096

10681097
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -1143,12 +1172,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
11431172
local_crates
11441173
}
11451174

1146-
/// Helper function used inside the shims of foreign functions to check that
1147-
/// `target_os` is a supported UNIX OS.
1148-
pub fn target_os_is_unix(target_os: &str) -> bool {
1149-
matches!(target_os, "linux" | "macos" | "freebsd" | "android")
1150-
}
1151-
11521175
pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
11531176
// SIMD uses all-1 as pattern for "true". In two's complement,
11541177
// -1 has all its bits set to one and `from_int` will truncate or

src/tools/miri/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub use crate::machine::{
125125
};
126126
pub use crate::mono_hash_map::MonoHashMap;
127127
pub use crate::operator::EvalContextExt as _;
128-
pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs};
128+
pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
129129
pub use crate::range_map::RangeMap;
130130

131131
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be

src/tools/miri/src/provenance_gc.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,13 @@ pub struct LiveAllocs<'a, 'mir, 'tcx> {
157157

158158
impl LiveAllocs<'_, '_, '_> {
159159
pub fn is_live(&self, id: AllocId) -> bool {
160-
self.collected.contains(&id) ||
161-
self.ecx.is_alloc_live(id)
160+
self.collected.contains(&id) || self.ecx.is_alloc_live(id)
162161
}
163162
}
164163

165164
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
166165
pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
167166
fn run_provenance_gc(&mut self) {
168-
169167
// We collect all tags from various parts of the interpreter, but also
170168
let this = self.eval_context_mut();
171169

@@ -196,10 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
196194

197195
fn remove_unreachable_allocs(&mut self, allocs: FxHashSet<AllocId>) {
198196
let this = self.eval_context_mut();
199-
let allocs = LiveAllocs {
200-
ecx: this,
201-
collected: allocs,
202-
};
197+
let allocs = LiveAllocs { ecx: this, collected: allocs };
203198
this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
204199
this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs);
205200
if let Some(borrow_tracker) = &this.machine.borrow_tracker {

0 commit comments

Comments
 (0)