diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1687297bde7..887b2ac4b37 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -26,6 +26,10 @@ pub enum TerminationInfo { second: SpanData, second_crate: Symbol, }, + SymbolShimClashing { + link_name: Symbol, + span: SpanData, + }, } impl fmt::Display for TerminationInfo { @@ -39,6 +43,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), + SymbolShimClashing { link_name, .. } => write!( + f, + "found `{}` symbol definition that clashes with a built-in shim", + link_name + ), } } } @@ -79,7 +88,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedInIsolation(_) => Some("unsupported operation"), ExperimentalUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), - MultipleSymbolDefinitions { .. } => None, + MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; #[rustfmt::skip] let helps = match info { @@ -98,6 +107,8 @@ pub fn report_error<'tcx, 'mir>( (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), ], + SymbolShimClashing { link_name, span } => + vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], _ => vec![], }; (title, helps) diff --git a/src/helpers.rs b/src/helpers.rs index e0f273be343..b99a446577a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_span::Symbol; use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -677,6 +678,36 @@ fn handle_unsupported>(&mut self, error_msg: S) -> InterpResult<'t throw_unsup_format!("{}", error_msg.as_ref()); } } + + fn check_abi_and_shim_symbol_clash( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + ) -> InterpResult<'tcx, ()> { + self.check_abi(abi, exp_abi)?; + if let Some(body) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + throw_machine_stop!(TerminationInfo::SymbolShimClashing { + link_name, + span: body.span.data(), + }) + } + Ok(()) + } + + fn check_shim<'a, const N: usize>( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + args: &'a [OpTy<'tcx, Tag>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + { + self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; + check_arg_count(args) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index e866868d729..4ea374344c0 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,22 +1,23 @@ use crate::rustc_target::abi::LayoutOf as _; use crate::*; -use helpers::check_arg_count; use rustc_ast::ast::Mutability; use rustc_middle::ty::{self, TypeAndMut}; -use rustc_span::BytePos; -use rustc_target::abi::Size; +use rustc_span::{BytePos, Symbol}; +use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn handle_miri_get_backtrace( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref flags] = check_arg_count(args)?; + let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -71,12 +72,14 @@ fn handle_miri_get_backtrace( fn handle_miri_resolve_frame( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref ptr, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f81..f193751518e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,6 @@ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::check_arg_count; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -227,14 +226,13 @@ fn emulate_foreign_item( let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_start_panic(args, unwind)?; + this.handle_miri_start_panic(abi, link_name_sym, 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" => { - this.check_abi(abi, Abi::Rust)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; 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)?)); @@ -243,14 +241,17 @@ fn emulate_foreign_item( | "exit" | "ExitProcess" => { - this.check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; - let &[ref code] = check_arg_count(args)?; + let &[ref code] = this.check_shim(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }, link_name_sym, 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.into())); } "abort" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::C { unwind: false }, + link_name_sym, + )?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -270,7 +271,7 @@ fn emulate_foreign_item( }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -293,6 +294,7 @@ fn emulate_foreign_item( fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -305,8 +307,7 @@ fn emulate_foreign_item_by_name( match link_name { // Miri-specific extern functions "miri_static_root" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -317,28 +318,24 @@ fn emulate_foreign_item_by_name( // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_get_backtrace(args, dest)?; + this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_resolve_frame(args, dest)?; + this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; } // Standard C allocation "malloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref size] = check_arg_count(args)?; + let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref items, ref len] = check_arg_count(args)?; + let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -347,14 +344,12 @@ fn emulate_foreign_item_by_name( this.write_scalar(res, dest)?; } "free" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref old_ptr, ref new_size] = check_arg_count(args)?; + let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -365,8 +360,7 @@ fn emulate_foreign_item_by_name( // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -378,8 +372,7 @@ fn emulate_foreign_item_by_name( this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -393,8 +386,7 @@ fn emulate_foreign_item_by_name( this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -407,8 +399,7 @@ fn emulate_foreign_item_by_name( )?; } "__rust_realloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -428,8 +419,7 @@ fn emulate_foreign_item_by_name( // C memory handling functions "memcmp" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref left, ref right, ref n] = check_arg_count(args)?; + let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -449,8 +439,7 @@ fn emulate_foreign_item_by_name( this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -468,8 +457,7 @@ fn emulate_foreign_item_by_name( } } "memchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -486,8 +474,7 @@ fn emulate_foreign_item_by_name( } } "strlen" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -503,8 +490,7 @@ fn emulate_foreign_item_by_name( | "asinf" | "atanf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { @@ -524,8 +510,7 @@ fn emulate_foreign_item_by_name( | "hypotf" | "atan2f" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -547,8 +532,7 @@ fn emulate_foreign_item_by_name( | "asin" | "atan" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { @@ -568,8 +552,7 @@ fn emulate_foreign_item_by_name( | "hypot" | "atan2" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -585,8 +568,7 @@ fn emulate_foreign_item_by_name( | "ldexp" | "scalbn" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref x, ref exp] = check_arg_count(args)?; + let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -607,13 +589,11 @@ fn emulate_foreign_item_by_name( // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref arg] = check_arg_count(args)?; + let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") @@ -627,8 +607,8 @@ fn emulate_foreign_item_by_name( // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 15620c73f0d..68b648f3271 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -15,6 +15,7 @@ use rustc_ast::Mutability; use rustc_middle::{mir, ty}; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -40,6 +41,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -48,7 +51,7 @@ fn handle_miri_start_panic( trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let &[ref payload] = check_arg_count(args)?; + let &[ref payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2ecea4d9f41..45e3d502a29 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,11 +1,11 @@ use log::trace; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -16,6 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -26,52 +27,45 @@ fn emulate_foreign_item_by_name( match link_name { // Environment related shims "getenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; + let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref buf, ref size] = check_arg_count(args)?; + let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref flag, ref mode] = check_arg_count(args)?; + let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref count] = check_arg_count(args)?; + let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -79,8 +73,7 @@ fn emulate_foreign_item_by_name( this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref n] = check_arg_count(args)?; + let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -90,71 +83,60 @@ fn emulate_foreign_item_by_name( this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref target, ref linkpath] = check_arg_count(args)?; + let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref oldpath, ref newpath] = check_arg_count(args)?; + let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref mode] = check_arg_count(args)?; + let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp] = check_arg_count(args)?; + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; + let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; + let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ret, ref align, ref size] = check_arg_count(args)?; + let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -184,8 +166,7 @@ fn emulate_foreign_item_by_name( // Dynamic symbol loading "dlsym" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref handle, ref symbol] = check_arg_count(args)?; + let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.read_c_str(symbol)?; @@ -199,8 +180,7 @@ fn emulate_foreign_item_by_name( // Querying system information "sysconf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -225,8 +205,7 @@ fn emulate_foreign_item_by_name( // Thread-local storage "pthread_key_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref dtor] = check_arg_count(args)?; + let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -254,24 +233,21 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; } "pthread_key_delete" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -283,178 +259,149 @@ fn emulate_foreign_item_by_name( // Synchronization primitives "pthread_mutexattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref kind] = check_arg_count(args)?; + let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex, ref attr] = check_arg_count(args)?; + let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref attr] = check_arg_count(args)?; + let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex] = check_arg_count(args)?; + let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; + let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; + let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref retval] = check_arg_count(args)?; + let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_self(dest)?; } "sched_yield" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref req, ref rem] = check_arg_count(args)?; + let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -463,8 +410,7 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; } "pthread_atfork" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; + let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -476,8 +422,7 @@ fn emulate_foreign_item_by_name( // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _attr, ref guard_size] = check_arg_count(args)?; + let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -489,37 +434,33 @@ fn emulate_foreign_item_by_name( | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_] = check_arg_count(args)?; + let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _, _] = check_arg_count(args)?; + let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 68ae704fb04..9af97103e07 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,7 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -24,8 +25,7 @@ fn emulate_foreign_item_by_name( match link_name { // errno "__errno_location" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -34,33 +34,33 @@ fn emulate_foreign_item_by_name( // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; + let &[ref fd, ref offset, ref len, ref advice] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -69,26 +69,26 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; } "sync_file_range" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; + let &[ref fd, ref offset, ref nbytes, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Time related shims "clock_gettime" => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. - let &[ref clk_id, ref tp] = check_arg_count(args)?; + let &[ref clk_id, ref tp] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information "pthread_attr_getstack" => { - this.check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; + let &[ref attr_place, ref addr_place, ref size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -108,27 +108,27 @@ fn emulate_foreign_item_by_name( // Threading "prctl" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; + let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Dynamically invoked syscalls "syscall" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -192,13 +192,13 @@ fn emulate_foreign_item_by_name( // Miscelanneous "getrandom" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; + let &[ref pid, ref cpusetsize, ref mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -211,8 +211,8 @@ fn emulate_foreign_item_by_name( // 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. "pthread_getattr_np" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _thread, ref _attr] = check_arg_count(args)?; + let &[ref _thread, ref _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 313d38c80b6..37de757e9b8 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,8 +1,8 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -12,6 +12,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -22,100 +23,95 @@ fn emulate_foreign_item_by_name( match link_name { // errno "__error" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims "close" | "close$NOCANCEL" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref result] = check_arg_count(args)?; + let &[ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf] = check_arg_count(args)?; + let &[ref fd, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref tv, ref tz] = check_arg_count(args)?; + let &[ref tv, ref tz] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref info] = check_arg_count(args)?; + let &[ref info] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dtor, ref data] = check_arg_count(args)?; + let &[ref dtor, ref data] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -125,15 +121,15 @@ fn emulate_foreign_item_by_name( // Querying system information "pthread_get_stackaddr_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -141,8 +137,8 @@ fn emulate_foreign_item_by_name( // Threading "pthread_setname_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -150,9 +146,9 @@ fn emulate_foreign_item_by_name( // 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. "mmap" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; + let &[ref addr, _, _, _, _, _] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 02f9bb8fff2..eaf1136669f 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,11 +1,11 @@ use std::iter; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -29,55 +30,54 @@ fn emulate_foreign_item_by_name( match link_name { // Environment related shims "GetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref buf, ref size] = check_arg_count(args)?; + let &[ref name, ref buf, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref value] = check_arg_count(args)?; + let &[ref name, ref value] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref env_block] = check_arg_count(args)?; + let &[ref env_block] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref size, ref buf] = check_arg_count(args)?; + let &[ref size, ref buf] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref which] = check_arg_count(args)?; + let &[ref which] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - check_arg_count(args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -111,8 +111,8 @@ fn emulate_foreign_item_by_name( // Allocation "HeapAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -121,8 +121,8 @@ fn emulate_foreign_item_by_name( this.write_scalar(res, dest)?; } "HeapFree" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -130,8 +130,8 @@ fn emulate_foreign_item_by_name( this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -142,22 +142,22 @@ fn emulate_foreign_item_by_name( // errno "SetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref error] = check_arg_count(args)?; + let &[ref error] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref system_info] = check_arg_count(args)?; + let &[ref system_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -172,25 +172,25 @@ fn emulate_foreign_item_by_name( // Thread-local storage "TlsAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -202,8 +202,8 @@ fn emulate_foreign_item_by_name( // Access to command-line arguments "GetCommandLineW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -212,65 +212,65 @@ fn emulate_foreign_item_by_name( // Time related shims "GetSystemTimeAsFileTime" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref LPFILETIME] = check_arg_count(args)?; + let &[ref LPFILETIME] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpPerformanceCount] = check_arg_count(args)?; + let &[ref lpPerformanceCount] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpFrequency] = check_arg_count(args)?; + let &[ref lpFrequency] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Synchronization primitives "AcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } // Dynamic symbol loading "GetProcAddress" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref hModule, ref lpProcName] = check_arg_count(args)?; + let &[ref hModule, ref lpProcName] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -284,16 +284,16 @@ fn emulate_foreign_item_by_name( // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr, ref len] = check_arg_count(args)?; + let &[ref ptr, ref len] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref algorithm, ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -313,9 +313,9 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. - let &[ref console, ref buffer_info] = check_arg_count(args)?; + let &[ref console, ref buffer_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -323,9 +323,9 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; } "GetConsoleMode" => { - this.check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. - let &[ref console, ref mode] = check_arg_count(args)?; + let &[ref console, ref mode] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -333,8 +333,8 @@ fn emulate_foreign_item_by_name( this.write_null(dest)?; } "SwitchToThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -342,7 +342,11 @@ fn emulate_foreign_item_by_name( // Better error for attempts to create a thread "CreateThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::System { unwind: false }, + link_name_sym, + )?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); @@ -351,29 +355,29 @@ fn emulate_foreign_item_by_name( // 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() => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; + let &[ref _hConsoleOutput, ref _wAttribute] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _First, ref _Handler] = check_arg_count(args)?; + let &[ref _First, ref _Handler] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[_StackSizeInBytes] = check_arg_count(args)?; + let &[_StackSizeInBytes] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } @@ -383,9 +387,9 @@ fn emulate_foreign_item_by_name( | "DeleteCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, @@ -396,9 +400,9 @@ fn emulate_foreign_item_by_name( // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs new file mode 100644 index 00000000000..c46d57cee0d --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs @@ -0,0 +1,15 @@ +#[no_mangle] +extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { + //~^ HELP the `malloc` symbol is defined here + unreachable!() +} + +fn main() { + extern "C" { + fn malloc(_: usize) -> *mut std::ffi::c_void; + } + unsafe { + malloc(0); + //~^ ERROR found `malloc` symbol definition that clashes with a built-in shim + } +}