From 6ac32f272e086fd93b066a0d1461839fbbfd08d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jan 2024 09:37:00 +0100 Subject: [PATCH 1/3] refactor extern static handling --- ci/ci.sh | 5 +-- src/machine.rs | 71 +--------------------------------- src/shims/extern_static.rs | 78 ++++++++++++++++++++++++++++++++++++++ src/shims/mod.rs | 1 + 4 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 src/shims/extern_static.rs diff --git a/ci/ci.sh b/ci/ci.sh index 08fce334e0..6bcc68ebf7 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -121,9 +121,8 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests # Some targets are only partially supported. - # FIXME: freeBSD disabled due to https://github.com/rust-lang/miri/issues/3276 - #MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align - #MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align + MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm diff --git a/src/machine.rs b/src/machine.rs index 4a878f4a36..8aa7c88f1c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -691,7 +691,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>, @@ -701,75 +701,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 } diff --git a/src/shims/extern_static.rs b/src/shims/extern_static.rs new file mode 100644 index 0000000000..61541a655d --- /dev/null +++ b/src/shims/extern_static.rs @@ -0,0 +1,78 @@ +//! 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" => { + // "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(()) + } +} diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 1e9d927e1a..2e0383a569 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -10,6 +10,7 @@ pub mod windows; mod x86; pub mod env; +pub mod extern_static; pub mod os_str; pub mod panic; pub mod time; From f239806f68ffb56617167e2209017fe25538b566 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jan 2024 09:37:18 +0100 Subject: [PATCH 2/3] add __cxa_thread_atexit_impl on freebsd --- src/shims/extern_static.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/extern_static.rs b/src/shims/extern_static.rs index 61541a655d..0284e5b606 100644 --- a/src/shims/extern_static.rs +++ b/src/shims/extern_static.rs @@ -49,6 +49,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ); } "freebsd" => { + Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?; // "environ" Self::add_extern_static( this, From 90ae4609ba9f3f0eeb7f7bcda10c48dc0e466cfa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jan 2024 10:16:49 +0100 Subject: [PATCH 3/3] a bit of refactoring for find_mir_or_eval_fn --- src/lib.rs | 1 - src/machine.rs | 16 +++++++++++++++- src/shims/mod.rs | 41 ----------------------------------------- 3 files changed, 15 insertions(+), 43 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b0b6d99436..057b883a3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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, diff --git a/src/machine.rs b/src/machine.rs index 8aa7c88f1c..567ac6cff6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -920,7 +920,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ret: Option, 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)] diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2e0383a569..ea6120f757 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -15,44 +15,3 @@ 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, - 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))) - } -}