Skip to content

Commit

Permalink
Auto merge of #120451 - RalfJung:miri, r=RalfJung
Browse files Browse the repository at this point in the history
Miri subtree update

r? `@ghost`
  • Loading branch information
bors committed Jan 29, 2024
2 parents 55807f7 + d85d147 commit 2aadd62
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 172 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/sysroots.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Tier 2 sysroots

on: push
# schedule:
# - cron: '44 4 * * *' # At 4:44 UTC every day.
on:
schedule:
- cron: '44 4 * * *' # At 4:44 UTC every day.

defaults:
run:
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ Definite bugs found:
* [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186)
* [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084)
* [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460)
* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138)

Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):

Expand Down
9 changes: 4 additions & 5 deletions cargo-miri/src/phases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,11 +501,10 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
// Set missing env vars. We prefer build-time env vars over run-time ones; see
// <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
for (name, val) in info.env {
// `CARGO_MAKEFLAGS` contains information about how to reach the
// jobserver, but by the time the program is being run, that jobserver
// no longer exists. Hence we shouldn't forward this.
// FIXME: Miri builds the final crate without a jobserver.
// This may be fixed with github.com/rust-lang/cargo/issues/12597.
// `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
// the program is being run, that jobserver no longer exists (cargo only runs the jobserver
// for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
// Also see <https://github.com/rust-lang/rust/pull/113730>.
if name == "CARGO_MAKEFLAGS" {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98
dd2559e08e1530806740931037d6bb83ef956161
19 changes: 17 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

/// Helper function to get a `windows` constant as a `Scalar`.
fn eval_windows(&self, module: &str, name: &str) -> Scalar<Provenance> {
self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal","windows", module, name])
self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
}

/// Helper function to get a `windows` constant as a `u32`.
Expand Down Expand Up @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
let this = self.eval_context_ref();
let ty = this
.resolve_path(&["std", "sys", "pal","windows", "c", name], Namespace::TypeNS)
.resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
.ty(*this.tcx, ty::ParamEnv::reveal_all());
this.layout_of(ty).unwrap()
}
Expand All @@ -270,6 +270,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
bug!("No field named {} in type {}", name, base.layout().ty);
}

/// Search if `base` (which must be a struct or union type) contains the `name` field.
fn projectable_has_field<P: Projectable<'tcx, Provenance>>(
&self,
base: &P,
name: &str,
) -> bool {
let adt = base.layout().ty.ty_adt_def().unwrap();
for field in adt.non_enum_variant().fields.iter() {
if field.name.as_str() == name {
return true;
}
}
false
}

/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
/// this method is fine for almost all integer types.
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
pub use crate::shims::time::EvalContextExt as _;
pub use crate::shims::tls::TlsData;
pub use crate::shims::EvalContextExt as _;

pub use crate::borrow_tracker::stacked_borrows::{
EvalContextExt as _, Item, Permission, Stack, Stacks,
Expand Down
95 changes: 21 additions & 74 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use std::process;

use either::Either;
use rand::rngs::StdRng;
use rand::SeedableRng;
use rand::Rng;
use rand::SeedableRng;

use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -83,7 +83,8 @@ pub struct FrameExtra<'tcx> {
impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Omitting `timing`, it does not support `Debug`.
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = self;
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } =
self;
f.debug_struct("FrameData")
.field("borrow_tracker", borrow_tracker)
.field("catch_unwind", catch_unwind)
Expand All @@ -93,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {

impl VisitProvenance for FrameExtra<'_> {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = self;
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } =
self;

catch_unwind.visit_provenance(visit);
borrow_tracker.visit_provenance(visit);
Expand Down Expand Up @@ -710,7 +712,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
Ok(())
}

fn add_extern_static(
pub(crate) fn add_extern_static(
this: &mut MiriInterpCx<'mir, 'tcx>,
name: &str,
ptr: Pointer<Option<Provenance>>,
Expand All @@ -720,75 +722,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
}

fn alloc_extern_static(
this: &mut MiriInterpCx<'mir, 'tcx>,
name: &str,
val: ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx> {
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
this.write_immediate(*val, &place)?;
Self::add_extern_static(this, name, place.ptr());
Ok(())
}

/// Sets up the "extern statics" for this machine.
fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
// "__rust_no_alloc_shim_is_unstable"
let val = ImmTy::from_int(0, this.machine.layouts.u8);
Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;

match this.tcx.sess.target.os.as_ref() {
"linux" => {
// "environ"
Self::add_extern_static(
this,
"environ",
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
);
// A couple zero-initialized pointer-sized extern statics.
// Most of them are for weak symbols, which we all set to null (indicating that the
// symbol is not supported, and triggering fallback code which ends up calling a
// syscall that we do support).
for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"]
{
let val = ImmTy::from_int(0, this.machine.layouts.usize);
Self::alloc_extern_static(this, name, val)?;
}
}
"freebsd" => {
// "environ"
Self::add_extern_static(
this,
"environ",
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
);
}
"android" => {
// "signal" -- just needs a non-zero pointer value (function does not even get called),
// but we arrange for this to be callable anyway (it will then do nothing).
let layout = this.machine.layouts.const_raw_ptr;
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
Self::alloc_extern_static(this, "signal", val)?;
// A couple zero-initialized pointer-sized extern statics.
// Most of them are for weak symbols, which we all set to null (indicating that the
// symbol is not supported, and triggering fallback code.)
for name in &["bsd_signal"] {
let val = ImmTy::from_int(0, this.machine.layouts.usize);
Self::alloc_extern_static(this, name, val)?;
}
}
"windows" => {
// "_tls_used"
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
let val = ImmTy::from_int(0, this.machine.layouts.u8);
Self::alloc_extern_static(this, "_tls_used", val)?;
}
_ => {} // No "extern statics" supported on this target
}
Ok(())
}

pub(crate) fn communicate(&self) -> bool {
self.isolated_op == IsolatedOp::Allow
}
Expand Down Expand Up @@ -1009,7 +942,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind)
// For foreign items, try to see if we can emulate them.
if ecx.tcx.is_foreign_item(instance.def_id()) {
// An external function call that does not have a MIR body. We either find MIR elsewhere
// or emulate its effect.
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
// foreign function
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
let link_name = ecx.item_link_name(instance.def_id());
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
}

// Otherwise, load the MIR.
Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
}

#[inline(always)]
Expand Down
2 changes: 1 addition & 1 deletion src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

Ok(match bin_op {
Eq | Ne | Lt | Le | Gt | Ge => {
assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for`
assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for`
let size = this.pointer_size();
// Just compare the bits. ScalarPairs are compared lexicographically.
// We thus always compare pairs and simply fill scalars up with 0.
Expand Down
79 changes: 79 additions & 0 deletions src/shims/extern_static.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Provides the `extern static` that this platform expects.

use crate::*;

impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
fn alloc_extern_static(
this: &mut MiriInterpCx<'mir, 'tcx>,
name: &str,
val: ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx> {
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
this.write_immediate(*val, &place)?;
Self::add_extern_static(this, name, place.ptr());
Ok(())
}

/// Zero-initialized pointer-sized extern statics are pretty common.
/// Most of them are for weak symbols, which we all set to null (indicating that the
/// symbol is not supported, and triggering fallback code which ends up calling a
/// syscall that we do support).
fn null_ptr_extern_statics(
this: &mut MiriInterpCx<'mir, 'tcx>,
names: &[&str],
) -> InterpResult<'tcx> {
for name in names {
let val = ImmTy::from_int(0, this.machine.layouts.usize);
Self::alloc_extern_static(this, name, val)?;
}
Ok(())
}

/// Sets up the "extern statics" for this machine.
pub fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
// "__rust_no_alloc_shim_is_unstable"
let val = ImmTy::from_int(0, this.machine.layouts.u8);
Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;

match this.tcx.sess.target.os.as_ref() {
"linux" => {
Self::null_ptr_extern_statics(
this,
&["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"],
)?;
// "environ"
Self::add_extern_static(
this,
"environ",
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
);
}
"freebsd" => {
Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?;
// "environ"
Self::add_extern_static(
this,
"environ",
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
);
}
"android" => {
Self::null_ptr_extern_statics(this, &["bsd_signal"])?;
// "signal" -- just needs a non-zero pointer value (function does not even get called),
// but we arrange for this to call the `signal` function anyway.
let layout = this.machine.layouts.const_raw_ptr;
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
Self::alloc_extern_static(this, "signal", val)?;
}
"windows" => {
// "_tls_used"
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
let val = ImmTy::from_int(0, this.machine.layouts.u8);
Self::alloc_extern_static(this, "_tls_used", val)?;
}
_ => {} // No "extern statics" supported on this target
}
Ok(())
}
}
3 changes: 2 additions & 1 deletion src/shims/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// ```
// Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
"is_val_statically_known" => {
let [_] = check_arg_count(args)?;
let [arg] = check_arg_count(args)?;
this.validate_operand(arg)?;
let branch: bool = this.machine.rng.get_mut().gen();
this.write_scalar(Scalar::from_bool(branch), dest)?;
}
Expand Down
42 changes: 1 addition & 41 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,8 @@ pub mod windows;
mod x86;

pub mod env;
pub mod extern_static;
pub mod os_str;
pub mod panic;
pub mod time;
pub mod tls;

// End module management, begin local code

use log::trace;

use rustc_middle::{mir, ty};
use rustc_target::spec::abi::Abi;

use crate::*;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn find_mir_or_eval_fn(
&mut self,
instance: ty::Instance<'tcx>,
abi: Abi,
args: &[FnArg<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
let this = self.eval_context_mut();
trace!("eval_fn_call: {:#?}, {:?}", instance, dest);

// For foreign items, try to see if we can emulate them.
if this.tcx.is_foreign_item(instance.def_id()) {
// An external function call that does not have a MIR body. We either find MIR elsewhere
// or emulate its effect.
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
// foreign function
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
let link_name = this.item_link_name(instance.def_id());
return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
}

// Otherwise, load the MIR.
Ok(Some((this.load_mir(instance.def, None)?, instance)))
}
}
Loading

0 comments on commit 2aadd62

Please sign in to comment.