Skip to content

Commit

Permalink
Auto merge of #118284 - RalfJung:miri, r=RalfJung
Browse files Browse the repository at this point in the history
Miri subtree update
  • Loading branch information
bors committed Nov 25, 2023
2 parents 75d6afc + 42fbb70 commit d52378d
Show file tree
Hide file tree
Showing 64 changed files with 716 additions and 454 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Set the tag GC interval to 1 on linux
if: runner.os == 'Linux'
run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV

# Cache the global cargo directory, but NOT the local `target` directory which
# we cannot reuse anyway when the nightly changes (and it grows quite large
# over time).
Expand Down
19 changes: 14 additions & 5 deletions cargo-miri/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::env;
use std::ffi::OsStr;
use std::fmt::Write;
use std::path::PathBuf;
use std::process::{self, Command};

Expand Down Expand Up @@ -140,12 +141,20 @@ pub fn setup(
// Do the build.
if print_sysroot {
// Be silent.
} else if only_setup {
// We want to be explicit.
eprintln!("Preparing a sysroot for Miri (target: {target})...");
} else {
// We want to be quiet, but still let the user know that something is happening.
eprint!("Preparing a sysroot for Miri (target: {target})... ");
let mut msg = String::new();
write!(msg, "Preparing a sysroot for Miri (target: {target})").unwrap();
if verbose > 0 {
write!(msg, " in {}", sysroot_dir.display()).unwrap();
}
write!(msg, "...").unwrap();
if only_setup {
// We want to be explicit.
eprintln!("{msg}");
} else {
// We want to be quiet, but still let the user know that something is happening.
eprint!("{msg} ");
}
}
SysrootBuilder::new(&sysroot_dir, target)
.build_mode(BuildMode::Check)
Expand Down
30 changes: 22 additions & 8 deletions ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,23 @@ endgroup

# Test
function run_tests {
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
else
begingroup "Testing host architecture"
fi

## ui test suite
./miri test
if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
# Host-only tests: running these on all targets is unlikely to catch more problems and would
# On the host and on Linux, also stress-test the GC.
if [ -z "${MIRI_TEST_TARGET:-}" ] || [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
else
./miri test
fi

# Host-only tests
if [ -z "${MIRI_TEST_TARGET:-}" ]; then
# Running these on all targets is unlikely to catch more problems and would
# cost a lot of CI time.

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

function run_tests_minimal {
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
else
begingroup "Testing MINIMAL host architecture: only testing $@"
echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
exit 1
fi

./miri test -- "$@"
Expand All @@ -99,16 +107,22 @@ function run_tests_minimal {
endgroup
}

# host
## Main Testing Logic ##

# Host target.
run_tests

# Extra targets.
# In particular, fully cover all tier 1 targets.
case $HOST_TARGET in
x86_64-unknown-linux-gnu)
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
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
# Some targets are only partially supported.
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
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
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
Expand Down
2 changes: 1 addition & 1 deletion miri-script/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ impl Command {
"This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
);
print!(
"To avoid that, abort now and set the `--rustc-git` flag to an existing rustc checkout. Proceed? [y/N] "
"To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
);
std::io::stdout().flush()?;
let mut answer = String::new();
Expand Down
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
820f06b21f8373060ff7b515715b8440a6a6c197
3668a8af1b81447c4afa1f82f60d7b94b71a549f
137 changes: 80 additions & 57 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ use std::time::Duration;

use log::trace;

use rustc_apfloat::ieee::{Double, Single};
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::{
self,
layout::{IntegerExt as _, LayoutOf, TyAndLayout},
IntTy, Ty, TyCtxt, UintTy,
layout::{LayoutOf, TyAndLayout},
FloatTy, IntTy, Ty, TyCtxt, UintTy,
};
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
use rustc_target::spec::abi::Abi;

use rand::RngCore;
Expand Down Expand Up @@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
/// if this is not the case.
fn assert_target_os_is_unix(&self, name: &str) {
assert!(
target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
"`{name}` is only available for supported UNIX family targets",
);
assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
}

fn target_os_is_unix(&self) -> bool {
self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
}

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

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

let val = match cast_to.ty.kind() {
// Unsigned
ty::Uint(t) => {
let size = Integer::from_uint_ty(this, *t).size();
let res = f.to_u128_r(size.bits_usize(), round, &mut false);
if res.status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
return None;
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Scalar::from_uint(res.value, size)
fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
this: &MiriInterpCx<'_, 'tcx>,
src: F,
cast_to: TyAndLayout<'tcx>,
round: rustc_apfloat::Round,
) -> (Scalar<Provenance>, rustc_apfloat::Status) {
let int_size = cast_to.layout.size;
match cast_to.ty.kind() {
// Unsigned
ty::Uint(_) => {
let res = src.to_u128_r(int_size.bits_usize(), round, &mut false);
(Scalar::from_uint(res.value, int_size), res.status)
}
}
// Signed
ty::Int(t) => {
let size = Integer::from_int_ty(this, *t).size();
let res = f.to_i128_r(size.bits_usize(), round, &mut false);
if res.status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
return None;
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Scalar::from_int(res.value, size)
// Signed
ty::Int(_) => {
let res = src.to_i128_r(int_size.bits_usize(), round, &mut false);
(Scalar::from_int(res.value, int_size), res.status)
}
// Nothing else
_ =>
span_bug!(
this.cur_span(),
"attempted float-to-int conversion with non-int output type {}",
cast_to.ty,
),
}
}

let (val, status) = match src.layout.ty.kind() {
// f32
ty::Float(FloatTy::F32) =>
float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
// f64
ty::Float(FloatTy::F64) =>
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
// Nothing else
_ =>
span_bug!(
this.cur_span(),
"attempted float-to-int conversion with non-int output type {}",
cast_to.ty,
"attempted float-to-int conversion with non-float input type {}",
src.layout.ty,
),
};
Some(ImmTy::from_scalar(val, cast_to))

if status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
Ok(None)
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Ok(Some(ImmTy::from_scalar(val, cast_to)))
}
}

/// Returns an integer type that is twice wide as `ty`
Expand All @@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
}
}

/// Checks that target feature `target_feature` is enabled.
///
/// If not enabled, emits an UB error that states that the feature is
/// required by `intrinsic`.
fn expect_target_feature_for_intrinsic(
&self,
intrinsic: Symbol,
target_feature: &str,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_ref();
if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
throw_ub_format!(
"attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
);
}
Ok(())
}
}

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

/// Helper function used inside the shims of foreign functions to check that
/// `target_os` is a supported UNIX OS.
pub fn target_os_is_unix(target_os: &str) -> bool {
matches!(target_os, "linux" | "macos" | "freebsd" | "android")
}

pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
// SIMD uses all-1 as pattern for "true". In two's complement,
// -1 has all its bits set to one and `from_int` will truncate or
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub use crate::machine::{
};
pub use crate::mono_hash_map::MonoHashMap;
pub use crate::operator::EvalContextExt as _;
pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs};
pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
pub use crate::range_map::RangeMap;

/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
Expand Down
9 changes: 2 additions & 7 deletions src/provenance_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,13 @@ pub struct LiveAllocs<'a, 'mir, 'tcx> {

impl LiveAllocs<'_, '_, '_> {
pub fn is_live(&self, id: AllocId) -> bool {
self.collected.contains(&id) ||
self.ecx.is_alloc_live(id)
self.collected.contains(&id) || self.ecx.is_alloc_live(id)
}
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
fn run_provenance_gc(&mut self) {

// We collect all tags from various parts of the interpreter, but also
let this = self.eval_context_mut();

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

fn remove_unreachable_allocs(&mut self, allocs: FxHashSet<AllocId>) {
let this = self.eval_context_mut();
let allocs = LiveAllocs {
ecx: this,
collected: allocs,
};
let allocs = LiveAllocs { ecx: this, collected: allocs };
this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs);
if let Some(borrow_tracker) = &this.machine.borrow_tracker {
Expand Down
Loading

0 comments on commit d52378d

Please sign in to comment.