From bc8d4dfa95ae10c3f7229c01710a9e8f838baaec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Oct 2023 09:15:48 +0200 Subject: [PATCH 1/3] refactor dlsym: dispatch symbols via the normal shim mechanism --- src/tools/miri/src/helpers.rs | 2 +- src/tools/miri/src/lib.rs | 4 +- src/tools/miri/src/machine.rs | 12 +-- src/tools/miri/src/shims/dlsym.rs | 48 ---------- src/tools/miri/src/shims/foreign_items.rs | 42 ++++++-- src/tools/miri/src/shims/mod.rs | 4 +- .../miri/src/shims/unix/android/dlsym.rs | 54 ----------- .../src/shims/unix/android/foreign_items.rs | 21 ++-- src/tools/miri/src/shims/unix/android/mod.rs | 1 - src/tools/miri/src/shims/unix/dlsym.rs | 55 ----------- .../miri/src/shims/unix/foreign_items.rs | 31 ++++-- .../miri/src/shims/unix/freebsd/dlsym.rs | 36 ------- .../src/shims/unix/freebsd/foreign_items.rs | 7 +- src/tools/miri/src/shims/unix/freebsd/mod.rs | 1 - src/tools/miri/src/shims/unix/linux/dlsym.rs | 40 -------- .../src/shims/unix/linux/foreign_items.rs | 8 +- src/tools/miri/src/shims/unix/linux/mod.rs | 1 - src/tools/miri/src/shims/unix/macos/dlsym.rs | 51 ---------- .../src/shims/unix/macos/foreign_items.rs | 31 +++--- src/tools/miri/src/shims/unix/macos/mod.rs | 1 - src/tools/miri/src/shims/unix/mod.rs | 1 - src/tools/miri/src/shims/windows/dlsym.rs | 82 ---------------- .../miri/src/shims/windows/foreign_items.rs | 95 +++++++++++++------ src/tools/miri/src/shims/windows/mod.rs | 1 - 24 files changed, 168 insertions(+), 461 deletions(-) delete mode 100644 src/tools/miri/src/shims/dlsym.rs delete mode 100644 src/tools/miri/src/shims/unix/android/dlsym.rs delete mode 100644 src/tools/miri/src/shims/unix/dlsym.rs delete mode 100644 src/tools/miri/src/shims/unix/freebsd/dlsym.rs delete mode 100644 src/tools/miri/src/shims/unix/linux/dlsym.rs delete mode 100644 src/tools/miri/src/shims/unix/macos/dlsym.rs delete mode 100644 src/tools/miri/src/shims/windows/dlsym.rs diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index fd9d57c487c0e..4146a9b41ae1c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -960,7 +960,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { self.check_abi(abi, exp_abi)?; if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { // If compiler-builtins is providing the symbol, then don't treat it as a clash. - // We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased + // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased // performance. Note that this means we won't catch any undefined behavior in // compiler-builtins when running other crates, but Miri can still be run on // compiler-builtins itself (or any crate that uses it as a normal dependency) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 816055cc4fe91..f1d8ce01bc24c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -8,6 +8,7 @@ #![feature(yeet_expr)] #![feature(nonzero_ops)] #![feature(round_ties_even)] +#![feature(let_chains)] #![feature(lint_reasons)] #![feature(trait_upcasting)] // Configure clippy and other lints @@ -86,9 +87,8 @@ pub use rustc_const_eval::interpret::*; // Resolve ambiguity. pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; -pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; -pub use crate::shims::foreign_items::EvalContextExt as _; +pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fb56e0135b4ca..54f90b2c03990 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -709,9 +709,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { "android" => { // "signal" let layout = this.machine.layouts.const_raw_ptr; - let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)? - .expect("`signal` must be an actual dlsym on android"); - let ptr = this.fn_ptr(FnVal::Other(dlsym)); + 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. @@ -867,7 +865,7 @@ impl<'mir, 'tcx> MiriInterpCxExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> { /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; - type ExtraFnVal = Dlsym; + type ExtraFnVal = DynSym; type FrameExtra = FrameExtra<'tcx>; type AllocExtra = AllocExtra<'tcx>; @@ -939,15 +937,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { #[inline(always)] fn call_extra_fn( ecx: &mut MiriInterpCx<'mir, 'tcx>, - fn_val: Dlsym, + fn_val: DynSym, abi: Abi, args: &[FnArg<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, ret: Option, - _unwind: mir::UnwindAction, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? - ecx.call_dlsym(fn_val, abi, &args, dest, ret) + ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind) } #[inline(always)] diff --git a/src/tools/miri/src/shims/dlsym.rs b/src/tools/miri/src/shims/dlsym.rs deleted file mode 100644 index 8bf6d24f85f31..0000000000000 --- a/src/tools/miri/src/shims/dlsym.rs +++ /dev/null @@ -1,48 +0,0 @@ -use rustc_middle::mir; -use rustc_target::spec::abi::Abi; - -use crate::helpers::target_os_is_unix; -use crate::*; -use shims::unix::dlsym as unix; -use shims::windows::dlsym as windows; - -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum Dlsym { - Posix(unix::Dlsym), - Windows(windows::Dlsym), -} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { - let name = &*String::from_utf8_lossy(name); - Ok(match target_os { - target if target_os_is_unix(target) => - unix::Dlsym::from_str(name, target)?.map(Dlsym::Posix), - "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), - os => bug!("dlsym not implemented for target_os {}", os), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - match dlsym { - Dlsym::Posix(dlsym) => - unix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), - Dlsym::Windows(dlsym) => - windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), - } - } -} diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 0c92ede40fd8c..e93521ac774c9 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -6,7 +6,7 @@ use rustc_apfloat::Float; use rustc_ast::expand::allocator::AllocatorKind; use rustc_hir::{ def::DefKind, - def_id::{CrateNum, DefId, LOCAL_CRATE}, + def_id::{CrateNum, LOCAL_CRATE}, }; use rustc_middle::middle::{ codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage, @@ -25,7 +25,18 @@ use super::backtrace::EvalContextExt as _; use crate::helpers::target_os_is_unix; use crate::*; -/// Returned by `emulate_foreign_item_by_name`. +/// Type of dynamic symbols (for `dlsym` et al) +#[derive(Debug, Copy, Clone)] +pub struct DynSym(Symbol); + +#[allow(clippy::should_implement_trait)] +impl DynSym { + pub fn from_str(name: &str) -> Self { + DynSym(Symbol::intern(name)) + } +} + +/// Returned by `emulate_foreign_item_inner`. pub enum EmulateByNameResult<'mir, 'tcx> { /// The caller is expected to jump to the return block. NeedsJumping, @@ -254,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// is delegated to another function. fn emulate_foreign_item( &mut self, - def_id: DefId, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, @@ -262,7 +273,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - let link_name = this.item_link_name(def_id); let tcx = this.tcx.tcx; // First: functions that diverge. @@ -322,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { }; // Second: functions that return immediately. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? { + match this.emulate_foreign_item_inner(link_name, abi, args, dest)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); @@ -345,6 +355,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(None) } + /// Emulates a call to a `DynSym`. + fn emulate_dyn_sym( + &mut self, + sym: DynSym, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ret: Option, + unwind: mir::UnwindAction, + ) -> InterpResult<'tcx> { + let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?; + assert!(res.is_none(), "DynSyms that delegate are not supported"); + Ok(()) + } + /// Emulates calling the internal __rust_* allocator functions fn emulate_allocator( &mut self, @@ -373,8 +398,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - /// Emulates calling a foreign item using its name. - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, @@ -1045,11 +1069,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => return match this.tcx.sess.target.os.as_ref() { target_os if target_os_is_unix(target_os) => - shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name( + shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), "windows" => - shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name( + shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), _ => Ok(EmulateByNameResult::NotSupported), diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 5a9574766f3d9..a031a2a25c968 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -9,7 +9,6 @@ pub mod unix; pub mod windows; mod x86; -pub mod dlsym; pub mod env; pub mod os_str; pub mod panic; @@ -58,7 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // 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? - return this.emulate_foreign_item(instance.def_id(), abi, &args, dest, ret, unwind); + 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. diff --git a/src/tools/miri/src/shims/unix/android/dlsym.rs b/src/tools/miri/src/shims/unix/android/dlsym.rs deleted file mode 100644 index 451bc0bd5e153..0000000000000 --- a/src/tools/miri/src/shims/unix/android/dlsym.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rustc_middle::mir; - -use crate::helpers::check_arg_count; -use crate::*; - -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum Dlsym { - signal, -} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match name { - "signal" => Some(Dlsym::signal), - "android_set_abort_message" => None, - _ => throw_unsup_format!("unsupported Android dlsym: {}", name), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "android"); - - match dlsym { - Dlsym::signal => { - if !this.frame_in_std() { - throw_unsup_format!( - "`signal` support is crude and just enough for libstd to work" - ); - } - - let [_sig, _func] = check_arg_count(args)?; - this.write_null(dest)?; - } - } - - log::trace!("{:?}", this.dump_place(dest)); - this.go_to_block(ret); - Ok(()) - } -} diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 756aed369f15b..b610cf97750f3 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -6,17 +6,26 @@ use shims::foreign_items::EmulateByNameResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub fn is_dyn_sym(name: &str) -> bool { + matches!(name, "signal") +} + pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, - _abi: Abi, - _args: &[OpTy<'tcx, Provenance>], - _dest: &PlaceTy<'tcx, Provenance>, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { - let _this = self.eval_context_mut(); - #[allow(clippy::match_single_binding)] + let this = self.eval_context_mut(); + match link_name.as_str() { + "signal" if this.frame_in_std() => { + let [_sig, _func] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs index 434f5f30b5a56..09c6507b24f84 100644 --- a/src/tools/miri/src/shims/unix/android/mod.rs +++ b/src/tools/miri/src/shims/unix/android/mod.rs @@ -1,2 +1 @@ -pub mod dlsym; pub mod foreign_items; diff --git a/src/tools/miri/src/shims/unix/dlsym.rs b/src/tools/miri/src/shims/unix/dlsym.rs deleted file mode 100644 index 8bc19d18f2b29..0000000000000 --- a/src/tools/miri/src/shims/unix/dlsym.rs +++ /dev/null @@ -1,55 +0,0 @@ -use rustc_middle::mir; -use rustc_target::spec::abi::Abi; - -use crate::*; -use shims::unix::android::dlsym as android; -use shims::unix::freebsd::dlsym as freebsd; -use shims::unix::linux::dlsym as linux; -use shims::unix::macos::dlsym as macos; - -#[derive(Debug, Copy, Clone)] -pub enum Dlsym { - Android(android::Dlsym), - FreeBsd(freebsd::Dlsym), - Linux(linux::Dlsym), - MacOs(macos::Dlsym), -} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option> { - Ok(match target_os { - "android" => android::Dlsym::from_str(name)?.map(Dlsym::Android), - "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), - "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), - "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), - _ => panic!("unsupported Unix OS {target_os}"), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - this.check_abi(abi, Abi::C { unwind: false })?; - - match dlsym { - Dlsym::Android(dlsym) => - android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::FreeBsd(dlsym) => - freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - } - } -} diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 4bcca5076cac2..06ffdbff4e6d0 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -1,4 +1,5 @@ use std::ffi::OsStr; +use std::str; use log::trace; @@ -14,9 +15,14 @@ use shims::unix::mem::EvalContextExt as _; use shims::unix::sync::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; +use shims::unix::android::foreign_items as android; +use shims::unix::freebsd::foreign_items as freebsd; +use shims::unix::linux::foreign_items as linux; +use shims::unix::macos::foreign_items as macos; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, @@ -25,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. #[rustfmt::skip] match link_name.as_str() { // Environment related shims @@ -230,9 +236,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; - let symbol_name = this.read_c_str(symbol)?; - if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { - let ptr = this.fn_ptr(FnVal::Other(dlsym)); + let name = this.read_c_str(symbol)?; + let is_dyn_sym = |name| match &*this.tcx.sess.target.os { + "android" => android::is_dyn_sym(name), + "freebsd" => freebsd::is_dyn_sym(name), + "linux" => linux::is_dyn_sym(name), + "macos" => macos::is_dyn_sym(name), + target_os => panic!("unsupported Unix OS {target_os}"), + }; + if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) { + let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; @@ -609,10 +622,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => { let target_os = &*this.tcx.sess.target.os; return match target_os { - "android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - "freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - "linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - "macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), + "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), + "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), + "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), _ => Ok(EmulateByNameResult::NotSupported), }; } diff --git a/src/tools/miri/src/shims/unix/freebsd/dlsym.rs b/src/tools/miri/src/shims/unix/freebsd/dlsym.rs deleted file mode 100644 index d759ffb8994b7..0000000000000 --- a/src/tools/miri/src/shims/unix/freebsd/dlsym.rs +++ /dev/null @@ -1,36 +0,0 @@ -use rustc_middle::mir; - -use crate::*; - -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum Dlsym {} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - throw_unsup_format!("unsupported FreeBSD dlsym: {}", name) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - _args: &[OpTy<'tcx, Provenance>], - _dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let _ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "freebsd"); - - match dlsym {} - - //trace!("{:?}", this.dump_place(**dest)); - //this.go_to_block(ret); - //Ok(()) - } -} diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index d755e5f10bae8..388b205267953 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -5,10 +5,13 @@ use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::unix::thread::EvalContextExt as _; -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub fn is_dyn_sym(_name: &str) -> bool { + false +} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, diff --git a/src/tools/miri/src/shims/unix/freebsd/mod.rs b/src/tools/miri/src/shims/unix/freebsd/mod.rs index 434f5f30b5a56..09c6507b24f84 100644 --- a/src/tools/miri/src/shims/unix/freebsd/mod.rs +++ b/src/tools/miri/src/shims/unix/freebsd/mod.rs @@ -1,2 +1 @@ -pub mod dlsym; pub mod foreign_items; diff --git a/src/tools/miri/src/shims/unix/linux/dlsym.rs b/src/tools/miri/src/shims/unix/linux/dlsym.rs deleted file mode 100644 index a96c14c142b25..0000000000000 --- a/src/tools/miri/src/shims/unix/linux/dlsym.rs +++ /dev/null @@ -1,40 +0,0 @@ -use rustc_middle::mir; - -use crate::*; - -#[derive(Debug, Copy, Clone)] -pub enum Dlsym {} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match name { - "__pthread_get_minstack" => None, - "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. - "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. - _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - _args: &[OpTy<'tcx, Provenance>], - _dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let _ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "linux"); - - match dlsym {} - - //trace!("{:?}", this.dump_place(**dest)); - //this.go_to_block(ret); - //Ok(()) - } -} diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 1bd751c59811f..9f5f6ea9bd091 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -12,9 +12,13 @@ use shims::unix::linux::sync::futex; use shims::unix::sync::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; +pub fn is_dyn_sym(_name: &str) -> bool { + false +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, @@ -23,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. match link_name.as_str() { // errno diff --git a/src/tools/miri/src/shims/unix/linux/mod.rs b/src/tools/miri/src/shims/unix/linux/mod.rs index 856ec226de8fc..fe18f1a32fd42 100644 --- a/src/tools/miri/src/shims/unix/linux/mod.rs +++ b/src/tools/miri/src/shims/unix/linux/mod.rs @@ -1,4 +1,3 @@ -pub mod dlsym; pub mod fd; pub mod foreign_items; pub mod mem; diff --git a/src/tools/miri/src/shims/unix/macos/dlsym.rs b/src/tools/miri/src/shims/unix/macos/dlsym.rs deleted file mode 100644 index fa8094528757e..0000000000000 --- a/src/tools/miri/src/shims/unix/macos/dlsym.rs +++ /dev/null @@ -1,51 +0,0 @@ -use rustc_middle::mir; - -use log::trace; - -use super::foreign_items::EvalContextExt as _; -use crate::*; -use helpers::check_arg_count; - -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -pub enum Dlsym { - getentropy, -} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match name { - "getentropy" => Some(Dlsym::getentropy), - _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "macos"); - - match dlsym { - Dlsym::getentropy => { - let [ptr, len] = check_arg_count(args)?; - let result = this.getentropy(ptr, len)?; - this.write_scalar(result, dest)?; - } - } - - trace!("{:?}", this.dump_place(dest)); - this.go_to_block(ret); - Ok(()) - } -} diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index b514097c5df08..cb0af4c827914 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -6,9 +6,13 @@ use shims::foreign_items::EmulateByNameResult; use shims::unix::fs::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; +pub fn is_dyn_sym(name: &str) -> bool { + matches!(name, "getentropy") +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, @@ -17,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. match link_name.as_str() { // errno @@ -113,8 +117,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "getentropy" => { let [buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.getentropy(buf, bufsize)?; - this.write_scalar(result, dest)?; + let buf = this.read_pointer(buf)?; + let bufsize = this.read_target_usize(bufsize)?; + + this.gen_random(buf, bufsize)?; + + this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS } // Access to command-line arguments @@ -206,19 +214,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(EmulateByNameResult::NeedsJumping) } - - fn getentropy( - &mut self, - buffer_op: &OpTy<'tcx, Provenance>, - length_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - this.assert_target_os("macos", "getentropy"); - - let ptr = this.read_pointer(buffer_op)?; - let len = this.read_target_usize(length_op)?; - this.gen_random(ptr, len)?; - - Ok(Scalar::from_i32(0)) // KERN_SUCCESS - } } diff --git a/src/tools/miri/src/shims/unix/macos/mod.rs b/src/tools/miri/src/shims/unix/macos/mod.rs index 434f5f30b5a56..09c6507b24f84 100644 --- a/src/tools/miri/src/shims/unix/macos/mod.rs +++ b/src/tools/miri/src/shims/unix/macos/mod.rs @@ -1,2 +1 @@ -pub mod dlsym; pub mod foreign_items; diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index a8ebd369abaaa..2f8014933521f 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -1,4 +1,3 @@ -pub mod dlsym; pub mod foreign_items; mod fs; diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs deleted file mode 100644 index e5afee35905d0..0000000000000 --- a/src/tools/miri/src/shims/windows/dlsym.rs +++ /dev/null @@ -1,82 +0,0 @@ -use rustc_middle::mir; -use rustc_target::spec::abi::Abi; - -use log::trace; - -use crate::helpers::check_arg_count; -use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; -use crate::shims::windows::sync::EvalContextExt as _; -use crate::*; - -#[derive(Debug, Copy, Clone)] -pub enum Dlsym { - SetThreadDescription, - WaitOnAddress, - WakeByAddressSingle, -} - -impl Dlsym { - // Returns an error for unsupported symbols, and None if this symbol - // should become a NULL pointer (pretend it does not exist). - pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match name { - "GetSystemTimePreciseAsFileTime" => None, - "SetThreadDescription" => Some(Dlsym::SetThreadDescription), - "WaitOnAddress" => Some(Dlsym::WaitOnAddress), - "WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle), - _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn call_dlsym( - &mut self, - dlsym: Dlsym, - abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "windows"); - - this.check_abi(abi, Abi::System { unwind: false })?; - - match dlsym { - Dlsym::SetThreadDescription => { - let [handle, name] = check_arg_count(args)?; - - let handle = this.read_scalar(handle)?; - - let name = this.read_wide_str(this.read_pointer(name)?)?; - - let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), - _ => this.invalid_handle("SetThreadDescription")?, - }; - - this.set_thread_name_wide(thread, &name); - - this.write_null(dest)?; - } - Dlsym::WaitOnAddress => { - let [ptr_op, compare_op, size_op, timeout_op] = check_arg_count(args)?; - - this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; - } - Dlsym::WakeByAddressSingle => { - let [ptr_op] = check_arg_count(args)?; - - this.WakeByAddressSingle(ptr_op)?; - } - } - - trace!("{:?}", this.dump_place(dest)); - this.go_to_block(ret); - Ok(()) - } -} diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index d76d01b07891a..fe2f48638b8f7 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -1,4 +1,5 @@ use std::iter; +use std::str; use rustc_span::Symbol; use rustc_target::abi::Size; @@ -10,9 +11,13 @@ use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use shims::windows::sync::EvalContextExt as _; use shims::windows::thread::EvalContextExt as _; +fn is_dyn_sym(name: &str) -> bool { + matches!(name, "SetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle") +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn emulate_foreign_item_by_name( + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, abi: Abi, @@ -21,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // Windows API stubs. // HANDLE = isize @@ -326,6 +331,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.WakeAllConditionVariable(condvar)?; } + "WaitOnAddress" => { + let [ptr_op, compare_op, size_op, timeout_op] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; + } + "WakeByAddressSingle" => { + let [ptr_op] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.WakeByAddressSingle(ptr_op)?; + } // Dynamic symbol loading "GetProcAddress" => { @@ -334,14 +351,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_target_isize(hModule)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { - let ptr = this.fn_ptr(FnVal::Other(dlsym)); + if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) { + let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } } + // Threading + "CreateThread" => { + let [security, stacksize, start, arg, flags, thread] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + let thread_id = + this.CreateThread(security, stacksize, start, arg, flags, thread)?; + + this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; + } + "WaitForSingleObject" => { + let [handle, timeout] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + let ret = this.WaitForSingleObject(handle, timeout)?; + this.write_scalar(Scalar::from_u32(ret), dest)?; + } + "GetCurrentThread" => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.write_scalar( + Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), + dest, + )?; + } + "SetThreadDescription" => { + let [handle, name] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + let handle = this.read_scalar(handle)?; + + let name = this.read_wide_str(this.read_pointer(name)?)?; + + let thread = match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), + _ => this.invalid_handle("SetThreadDescription")?, + }; + + this.set_thread_name_wide(thread, &name); + + this.write_null(dest)?; + } + // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. @@ -456,32 +517,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - // Threading - "CreateThread" => { - let [security, stacksize, start, arg, flags, thread] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - - let thread_id = - this.CreateThread(security, stacksize, start, arg, flags, thread)?; - - this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; - } - "WaitForSingleObject" => { - let [handle, timeout] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - - let ret = this.WaitForSingleObject(handle, timeout)?; - this.write_scalar(Scalar::from_u32(ret), dest)?; - } - "GetCurrentThread" => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - - this.write_scalar( - Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), - dest, - )?; - } - // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs index 40fe71b2dbd02..7688abe412b99 100644 --- a/src/tools/miri/src/shims/windows/mod.rs +++ b/src/tools/miri/src/shims/windows/mod.rs @@ -1,4 +1,3 @@ -pub mod dlsym; pub mod foreign_items; mod handle; From 099311ba5a15162d73afe9ebe62bdc463ebd76c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Oct 2023 09:20:51 +0200 Subject: [PATCH 2/3] make some things on foreign_items private --- src/tools/miri/src/shims/foreign_items.rs | 418 +++++++++--------- .../src/shims/unix/android/foreign_items.rs | 8 +- .../miri/src/shims/unix/foreign_items.rs | 8 +- .../src/shims/unix/freebsd/foreign_items.rs | 8 +- .../src/shims/unix/linux/foreign_items.rs | 10 +- .../src/shims/unix/macos/foreign_items.rs | 8 +- .../miri/src/shims/windows/foreign_items.rs | 8 +- src/tools/miri/src/shims/x86/mod.rs | 12 +- src/tools/miri/src/shims/x86/sse.rs | 8 +- src/tools/miri/src/shims/x86/sse2.rs | 8 +- src/tools/miri/src/shims/x86/sse3.rs | 8 +- src/tools/miri/src/shims/x86/ssse3.rs | 8 +- 12 files changed, 256 insertions(+), 256 deletions(-) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index e93521ac774c9..3462f03c30ffb 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -37,119 +37,129 @@ impl DynSym { } /// Returned by `emulate_foreign_item_inner`. -pub enum EmulateByNameResult<'mir, 'tcx> { +pub enum EmulateForeignItemResult { /// The caller is expected to jump to the return block. NeedsJumping, /// Jumping has already been taken care of. AlreadyJumped, - /// A MIR body has been found for the function. - MirBody(&'mir mir::Body<'tcx>, ty::Instance<'tcx>), /// The item is not supported. NotSupported, } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - /// Returns the minimum alignment for the target architecture for allocations of the given size. - fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { - let this = self.eval_context_ref(); - // List taken from `library/std/src/sys/common/alloc.rs`. - // This list should be kept in sync with the one from libstd. - let min_align = match this.tcx.sess.target.arch.as_ref() { - "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, - "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" => - 16, - arch => bug!("unsupported target architecture for malloc: `{}`", arch), + /// Emulates calling a foreign item, failing if the item is not supported. + /// This function will handle `goto_block` if needed. + /// Returns Ok(None) if the foreign item was completely handled + /// by this function. + /// Returns Ok(Some(body)) if processing the foreign item + /// is delegated to another function. + fn emulate_foreign_item( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ret: Option, + unwind: mir::UnwindAction, + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { + let this = self.eval_context_mut(); + let tcx = this.tcx.tcx; + + // First: functions that diverge. + let ret = match ret { + None => + match link_name.as_str() { + "miri_start_panic" => { + // `check_shim` happens inside `handle_miri_start_panic`. + this.handle_miri_start_panic(abi, link_name, args, unwind)?; + return Ok(None); + } + // This matches calls to the foreign item `panic_impl`. + // The implementation is provided by the function with the `#[panic_handler]` attribute. + "panic_impl" => { + // We don't use `check_shim` here because we are just forwarding to the lang + // item. Argument count checking will be performed when the returned `Body` is + // called. + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; + let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); + return Ok(Some(( + this.load_mir(panic_impl_instance.def, None)?, + panic_impl_instance, + ))); + } + #[rustfmt::skip] + | "exit" + | "ExitProcess" + => { + let exp_abi = if link_name.as_str() == "exit" { + Abi::C { unwind: false } + } else { + Abi::System { unwind: false } + }; + let [code] = this.check_shim(abi, exp_abi, link_name, args)?; + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway + let code = this.read_scalar(code)?.to_i32()?; + throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); + } + "abort" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) + } + _ => { + if let Some(body) = this.lookup_exported_symbol(link_name)? { + return Ok(Some(body)); + } + this.handle_unsupported(format!( + "can't call (diverging) foreign function: {link_name}" + ))?; + return Ok(None); + } + }, + Some(p) => p, }; - // Windows always aligns, even small allocations. - // Source: - // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big. - if kind == MiriMemoryKind::WinHeap || size >= min_align { - return Align::from_bytes(min_align).unwrap(); - } - // We have `size < min_align`. Round `size` *down* to the next power of two and use that. - fn prev_power_of_two(x: u64) -> u64 { - let next_pow2 = x.next_power_of_two(); - if next_pow2 == x { - // x *is* a power of two, just use that. - x - } else { - // x is between two powers, so next = 2*prev. - next_pow2 / 2 + + // Second: functions that return immediately. + match this.emulate_foreign_item_inner(link_name, abi, args, dest)? { + EmulateForeignItemResult::NeedsJumping => { + trace!("{:?}", this.dump_place(dest)); + this.go_to_block(ret); } - } - Align::from_bytes(prev_power_of_two(size)).unwrap() - } + EmulateForeignItemResult::AlreadyJumped => (), + EmulateForeignItemResult::NotSupported => { + if let Some(body) = this.lookup_exported_symbol(link_name)? { + return Ok(Some(body)); + } - fn malloc( - &mut self, - size: u64, - zero_init: bool, - kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { - let this = self.eval_context_mut(); - if size == 0 { - Ok(Pointer::null()) - } else { - let align = this.min_align(size, kind); - let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; - if zero_init { - // We just allocated this, the access is definitely in-bounds and fits into our address space. - this.write_bytes_ptr( - ptr.into(), - iter::repeat(0u8).take(usize::try_from(size).unwrap()), - ) - .unwrap(); + this.handle_unsupported(format!( + "can't call foreign function `{link_name}` on OS `{os}`", + os = this.tcx.sess.target.os, + ))?; + return Ok(None); } - Ok(ptr.into()) } + + Ok(None) } - fn free( + /// Emulates a call to a `DynSym`. + fn emulate_dyn_sym( &mut self, - ptr: Pointer>, - kind: MiriMemoryKind, + sym: DynSym, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ret: Option, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - if !this.ptr_is_null(ptr)? { - this.deallocate_ptr(ptr, None, kind.into())?; - } + let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?; + assert!(res.is_none(), "DynSyms that delegate are not supported"); Ok(()) } - fn realloc( - &mut self, - old_ptr: Pointer>, - new_size: u64, - kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { - let this = self.eval_context_mut(); - let new_align = this.min_align(new_size, kind); - if this.ptr_is_null(old_ptr)? { - if new_size == 0 { - Ok(Pointer::null()) - } else { - let new_ptr = - this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?; - Ok(new_ptr.into()) - } - } else { - if new_size == 0 { - this.deallocate_ptr(old_ptr, None, kind.into())?; - Ok(Pointer::null()) - } else { - let new_ptr = this.reallocate_ptr( - old_ptr, - None, - Size::from_bytes(new_size), - new_align, - kind.into(), - )?; - Ok(new_ptr.into()) - } - } - } - /// Lookup the body of a function that has `link_name` as the symbol name. fn lookup_exported_symbol( &mut self, @@ -244,6 +254,78 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } + fn malloc( + &mut self, + size: u64, + zero_init: bool, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + if size == 0 { + Ok(Pointer::null()) + } else { + let align = this.min_align(size, kind); + let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; + if zero_init { + // We just allocated this, the access is definitely in-bounds and fits into our address space. + this.write_bytes_ptr( + ptr.into(), + iter::repeat(0u8).take(usize::try_from(size).unwrap()), + ) + .unwrap(); + } + Ok(ptr.into()) + } + } + + fn free( + &mut self, + ptr: Pointer>, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if !this.ptr_is_null(ptr)? { + this.deallocate_ptr(ptr, None, kind.into())?; + } + Ok(()) + } + + fn realloc( + &mut self, + old_ptr: Pointer>, + new_size: u64, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + let new_align = this.min_align(new_size, kind); + if this.ptr_is_null(old_ptr)? { + if new_size == 0 { + Ok(Pointer::null()) + } else { + let new_ptr = + this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?; + Ok(new_ptr.into()) + } + } else { + if new_size == 0 { + this.deallocate_ptr(old_ptr, None, kind.into())?; + Ok(Pointer::null()) + } else { + let new_ptr = this.reallocate_ptr( + old_ptr, + None, + Size::from_bytes(new_size), + new_align, + kind.into(), + )?; + Ok(new_ptr.into()) + } + } + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Read bytes from a `(ptr, len)` argument fn read_byte_slice<'i>(&'i self, bytes: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, &'i [u8]> where @@ -257,129 +339,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(bytes) } - /// Emulates calling a foreign item, failing if the item is not supported. - /// This function will handle `goto_block` if needed. - /// Returns Ok(None) if the foreign item was completely handled - /// by this function. - /// Returns Ok(Some(body)) if processing the foreign item - /// is delegated to another function. - fn emulate_foreign_item( - &mut self, - link_name: Symbol, - abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - let this = self.eval_context_mut(); - let tcx = this.tcx.tcx; - - // First: functions that diverge. - let ret = match ret { - None => - match link_name.as_str() { - "miri_start_panic" => { - // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name, args, unwind)?; - return Ok(None); - } - // This matches calls to the foreign item `panic_impl`. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - // We don't use `check_shim` here because we are just forwarding to the lang - // item. Argument count checking will be performed when the returned `Body` is - // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; - let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(( - this.load_mir(panic_impl_instance.def, None)?, - panic_impl_instance, - ))); - } - #[rustfmt::skip] - | "exit" - | "ExitProcess" - => { - let exp_abi = if link_name.as_str() == "exit" { - Abi::C { unwind: false } - } else { - Abi::System { unwind: false } - }; - let [code] = this.check_shim(abi, exp_abi, link_name, args)?; - // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(code)?.to_i32()?; - throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); - } - "abort" => { - let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - throw_machine_stop!(TerminationInfo::Abort( - "the program aborted execution".to_owned() - )) - } - _ => { - if let Some(body) = this.lookup_exported_symbol(link_name)? { - return Ok(Some(body)); - } - this.handle_unsupported(format!( - "can't call (diverging) foreign function: {link_name}" - ))?; - return Ok(None); - } - }, - Some(p) => p, + /// Returns the minimum alignment for the target architecture for allocations of the given size. + fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { + let this = self.eval_context_ref(); + // List taken from `library/std/src/sys/common/alloc.rs`. + // This list should be kept in sync with the one from libstd. + let min_align = match this.tcx.sess.target.arch.as_ref() { + "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, + "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" => + 16, + arch => bug!("unsupported target architecture for malloc: `{}`", arch), }; - - // Second: functions that return immediately. - match this.emulate_foreign_item_inner(link_name, abi, args, dest)? { - EmulateByNameResult::NeedsJumping => { - trace!("{:?}", this.dump_place(dest)); - this.go_to_block(ret); - } - EmulateByNameResult::AlreadyJumped => (), - EmulateByNameResult::MirBody(mir, instance) => return Ok(Some((mir, instance))), - EmulateByNameResult::NotSupported => { - if let Some(body) = this.lookup_exported_symbol(link_name)? { - return Ok(Some(body)); - } - - this.handle_unsupported(format!( - "can't call foreign function `{link_name}` on OS `{os}`", - os = this.tcx.sess.target.os, - ))?; - return Ok(None); + // Windows always aligns, even small allocations. + // Source: + // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big. + if kind == MiriMemoryKind::WinHeap || size >= min_align { + return Align::from_bytes(min_align).unwrap(); + } + // We have `size < min_align`. Round `size` *down* to the next power of two and use that. + fn prev_power_of_two(x: u64) -> u64 { + let next_pow2 = x.next_power_of_two(); + if next_pow2 == x { + // x *is* a power of two, just use that. + x + } else { + // x is between two powers, so next = 2*prev. + next_pow2 / 2 } } - - Ok(None) - } - - /// Emulates a call to a `DynSym`. - fn emulate_dyn_sym( - &mut self, - sym: DynSym, - abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { - let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?; - assert!(res.is_none(), "DynSyms that delegate are not supported"); - Ok(()) + Align::from_bytes(prev_power_of_two(size)).unwrap() } /// Emulates calling the internal __rust_* allocator functions fn emulate_allocator( &mut self, default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); let Some(allocator_kind) = this.tcx.allocator_kind(()) else { // in real code, this symbol does not exist without an allocator - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateForeignItemResult::NotSupported); }; match allocator_kind { @@ -389,11 +389,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // and not execute any Miri shim. Somewhat unintuitively doing so is done // by returning `NotSupported`, which triggers the `lookup_exported_symbol` // fallback case in `emulate_foreign_item`. - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateForeignItemResult::NotSupported); } AllocatorKind::Default => { default(this)?; - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } } @@ -404,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // First deal with any external C functions in linked .so file. @@ -415,7 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. if this.call_external_c_fct(link_name, dest, args)? { - return Ok(EmulateByNameResult::NeedsJumping); + return Ok(EmulateForeignItemResult::NeedsJumping); } } @@ -615,7 +615,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "__rust_alloc" => return this.emulate_allocator(default), "miri_alloc" => { default(this)?; - return Ok(EmulateByNameResult::NeedsJumping); + return Ok(EmulateForeignItemResult::NeedsJumping); } _ => unreachable!(), } @@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } "miri_dealloc" => { default(this)?; - return Ok(EmulateByNameResult::NeedsJumping); + return Ok(EmulateForeignItemResult::NeedsJumping); } _ => unreachable!(), } @@ -1076,12 +1076,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), - _ => Ok(EmulateByNameResult::NotSupported), + _ => Ok(EmulateForeignItemResult::NotSupported), }, }; // We only fall through to here if we did *not* hit the `_` arm above, // i.e., if we actually emulated the function with one of the shims. - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } /// Check some basic requirements for this allocation request: diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index b610cf97750f3..66ce0d4ebdbc5 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} @@ -17,7 +17,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { @@ -26,10 +26,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } #[allow(unreachable_code)] - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 06ffdbff4e6d0..76021e9de95c4 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -9,7 +9,7 @@ use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; use shims::unix::fs::EvalContextExt as _; use shims::unix::mem::EvalContextExt as _; use shims::unix::sync::EvalContextExt as _; @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. @@ -626,11 +626,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - _ => Ok(EmulateByNameResult::NotSupported), + _ => Ok(EmulateForeignItemResult::NotSupported), }; } }; - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 388b205267953..869434e8876ed 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { @@ -17,7 +17,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { // Threading @@ -45,8 +45,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 9f5f6ea9bd091..17129c372ea61 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -4,7 +4,7 @@ use rustc_target::spec::abi::Abi; use crate::machine::SIGRTMAX; use crate::machine::SIGRTMIN; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; use shims::unix::fs::EvalContextExt as _; use shims::unix::linux::fd::EvalContextExt as _; use shims::unix::linux::mem::EvalContextExt as _; @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. @@ -186,7 +186,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } id => { this.handle_unsupported(format!("can't execute syscall with ID {id}"))?; - return Ok(EmulateByNameResult::AlreadyJumped); + return Ok(EmulateForeignItemResult::AlreadyJumped); } } } @@ -217,10 +217,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_null(dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), }; - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index cb0af4c827914..5881a3f46f295 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; use shims::unix::fs::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. @@ -209,9 +209,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(res, dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), }; - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index fe2f48638b8f7..759a412c16a25 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -6,7 +6,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use shims::windows::sync::EvalContextExt as _; use shims::windows::thread::EvalContextExt as _; @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. @@ -583,9 +583,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_null(dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 7c280109cb011..53a4a1ef28a7f 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::bool_to_simd_element; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; mod sse; mod sse2; @@ -22,7 +22,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); @@ -34,7 +34,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html "addcarry.32" | "addcarry.64" => { if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateForeignItemResult::NotSupported); } let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; @@ -60,7 +60,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html "subborrow.32" | "subborrow.64" => { if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateForeignItemResult::NotSupported); } let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; @@ -100,9 +100,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this, link_name, abi, args, dest, ); } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index fa722f4b75ecd..6f0b76059f10d 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -7,7 +7,7 @@ use rand::Rng as _; use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp}; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: @@ -19,7 +19,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap(); @@ -228,9 +228,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.write_scalar(Scalar::from_u32(res), dest)?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 261c947c8efd2..c6a847b5cf824 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -10,7 +10,7 @@ use rustc_target::spec::abi::Abi; use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp}; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: @@ -22,7 +22,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap(); @@ -797,9 +797,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index f5c30a521fa8b..a41de5dbf7ee5 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use super::horizontal_bin_op; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: @@ -17,7 +17,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse3.").unwrap(); @@ -83,8 +83,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: /*nonoverlapping*/ true, )?; } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index b01546722346b..dbc2b947b3322 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -4,7 +4,7 @@ use rustc_target::spec::abi::Abi; use super::horizontal_bin_op; use crate::*; -use shims::foreign_items::EmulateByNameResult; +use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: @@ -16,7 +16,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: abi: Abi, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + ) -> InterpResult<'tcx, EmulateForeignItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.ssse3.").unwrap(); @@ -192,8 +192,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.write_immediate(*res, &dest)?; } } - _ => return Ok(EmulateByNameResult::NotSupported), + _ => return Ok(EmulateForeignItemResult::NotSupported), } - Ok(EmulateByNameResult::NeedsJumping) + Ok(EmulateForeignItemResult::NeedsJumping) } } From 16cde069fc7e727dca3c6d8ec5077f0d2f6f928b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Oct 2023 09:38:50 +0200 Subject: [PATCH 3/3] allow dyn_sym in the files where they are defined; remove unreachable android code --- src/tools/miri/src/machine.rs | 3 ++- .../src/shims/unix/android/foreign_items.rs | 11 +++----- .../miri/src/shims/unix/foreign_items.rs | 26 +++++++++++++------ .../src/shims/unix/linux/foreign_items.rs | 4 +-- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 54f90b2c03990..bd7ec88fc1c3b 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -707,7 +707,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ); } "android" => { - // "signal" + // "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); diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 66ce0d4ebdbc5..f61ebd5a3a8dc 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -6,11 +6,12 @@ use shims::foreign_items::EmulateForeignItemResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub fn is_dyn_sym(name: &str) -> bool { - matches!(name, "signal") +pub fn is_dyn_sym(_name: &str) -> bool { + false } pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + #[allow(unused, clippy::match_single_binding)] // there isn't anything here yet fn emulate_foreign_item_inner( &mut self, link_name: Symbol, @@ -21,15 +22,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); match link_name.as_str() { - "signal" if this.frame_in_std() => { - let [_sig, _func] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_null(dest)?; - } _ => return Ok(EmulateForeignItemResult::NotSupported), } - #[allow(unreachable_code)] Ok(EmulateForeignItemResult::NeedsJumping) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 76021e9de95c4..f18fa1cbbb7ab 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -20,6 +20,23 @@ use shims::unix::freebsd::foreign_items as freebsd; use shims::unix::linux::foreign_items as linux; use shims::unix::macos::foreign_items as macos; +fn is_dyn_sym(name: &str, target_os: &str) -> bool { + match name { + // `signal` is set up as a weak symbol in `init_extern_statics` so we might as well allow it + // in `dlsym` as well. + "signal" => true, + // Give specific OSes a chance to allow their symbols. + _ => + match target_os { + "android" => android::is_dyn_sym(name), + "freebsd" => freebsd::is_dyn_sym(name), + "linux" => linux::is_dyn_sym(name), + "macos" => macos::is_dyn_sym(name), + target_os => panic!("unsupported Unix OS {target_os}"), + }, + } +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn emulate_foreign_item_inner( @@ -237,14 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; - let is_dyn_sym = |name| match &*this.tcx.sess.target.os { - "android" => android::is_dyn_sym(name), - "freebsd" => freebsd::is_dyn_sym(name), - "linux" => linux::is_dyn_sym(name), - "macos" => macos::is_dyn_sym(name), - target_os => panic!("unsupported Unix OS {target_os}"), - }; - if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) { + if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) { let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; } else { diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 17129c372ea61..6937e0f089ec8 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -12,8 +12,8 @@ use shims::unix::linux::sync::futex; use shims::unix::sync::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; -pub fn is_dyn_sym(_name: &str) -> bool { - false +pub fn is_dyn_sym(name: &str) -> bool { + matches!(name, "getrandom") } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}