Disallow #[no_mangle]/#[export_name = ...] functions that have the same symbol name as built-in shims

This commit is contained in:
hyd-dev 2021-06-06 15:25:16 +08:00
parent 6aef1d687d
commit ce7040075a
No known key found for this signature in database
GPG Key ID: 74FA7FD5B8DA14B8
10 changed files with 320 additions and 336 deletions

View File

@ -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)

View File

@ -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<S: AsRef<str>>(&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.

View File

@ -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 {

View File

@ -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),
}
};

View File

@ -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");

View File

@ -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!(),
}
}

View File

@ -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)?;
}

View File

@ -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)?;
}

View File

@ -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,

View File

@ -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
}
}