Only pass Symbol to emulate_foreign_item_by_name
This commit is contained in:
parent
34603e586f
commit
a67a65359f
6 changed files with 190 additions and 191 deletions
|
|
@ -723,6 +723,11 @@ where
|
|||
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
|
||||
}
|
||||
|
||||
/// Strip linker suffixes (seen on 32-bit macOS).
|
||||
pub fn strip_linker_suffix(link_name: &str) -> &str {
|
||||
link_name.trim_end_matches("$UNIX2003")
|
||||
}
|
||||
|
||||
pub fn isolation_abort_error(name: &str) -> InterpResult<'static> {
|
||||
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
|
||||
"{} not available when isolation is enabled",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use rustc_target::{
|
|||
|
||||
use super::backtrace::EvalContextExt as _;
|
||||
use crate::*;
|
||||
use helpers::strip_linker_suffix;
|
||||
|
||||
/// Returned by `emulate_foreign_item_by_name`.
|
||||
pub enum EmulateByNameResult {
|
||||
|
|
@ -215,8 +216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
.first_attr_value_str_by_name(&attrs, sym::link_name)
|
||||
.unwrap_or_else(|| this.tcx.item_name(def_id));
|
||||
let link_name = link_name_sym.as_str();
|
||||
// Strip linker suffixes (seen on 32-bit macOS).
|
||||
let link_name = link_name.trim_end_matches("$UNIX2003");
|
||||
let link_name = strip_linker_suffix(&link_name);
|
||||
let tcx = this.tcx.tcx;
|
||||
|
||||
// First: functions that diverge.
|
||||
|
|
@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
};
|
||||
|
||||
// Second: functions that return.
|
||||
match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? {
|
||||
match this.emulate_foreign_item_by_name(link_name_sym, abi, args, dest, ret)? {
|
||||
EmulateByNameResult::NeedsJumping => {
|
||||
trace!("{:?}", this.dump_place(**dest));
|
||||
this.go_to_block(ret);
|
||||
|
|
@ -296,8 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
/// Emulates calling a foreign item using its name.
|
||||
fn emulate_foreign_item_by_name(
|
||||
&mut self,
|
||||
link_name: &str,
|
||||
link_name_sym: Symbol,
|
||||
link_name: Symbol,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
|
|
@ -307,10 +306,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Here we dispatch all the shims for foreign functions. If you have a platform specific
|
||||
// shim, add it to the corresponding submodule.
|
||||
match link_name {
|
||||
let shim_name = link_name.as_str();
|
||||
let shim_name = strip_linker_suffix(&shim_name);
|
||||
match shim_name {
|
||||
// Miri-specific extern functions
|
||||
"miri_static_root" => {
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?;
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
let ptr = this.force_ptr(ptr)?;
|
||||
if ptr.offset != Size::ZERO {
|
||||
|
|
@ -322,25 +323,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Obtains a Miri backtrace. See the README for details.
|
||||
"miri_get_backtrace" => {
|
||||
// `check_shim` happens inside `handle_miri_get_backtrace`.
|
||||
this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?;
|
||||
this.handle_miri_get_backtrace(abi, link_name, args, dest)?;
|
||||
}
|
||||
|
||||
// Resolves a Miri backtrace frame. See the README for details.
|
||||
"miri_resolve_frame" => {
|
||||
// `check_shim` happens inside `handle_miri_resolve_frame`.
|
||||
this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?;
|
||||
this.handle_miri_resolve_frame(abi, link_name, args, dest)?;
|
||||
}
|
||||
|
||||
|
||||
// Standard C allocation
|
||||
"malloc" => {
|
||||
let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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" => {
|
||||
let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let items = this.read_scalar(items)?.to_machine_usize(this)?;
|
||||
let len = this.read_scalar(len)?.to_machine_usize(this)?;
|
||||
let size =
|
||||
|
|
@ -349,12 +350,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
"free" => {
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
this.free(ptr, MiriMemoryKind::C)?;
|
||||
}
|
||||
"realloc" => {
|
||||
let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// (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" => {
|
||||
let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?;
|
||||
let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, 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)?;
|
||||
|
|
@ -377,7 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(ptr, dest)?;
|
||||
}
|
||||
"__rust_alloc_zeroed" => {
|
||||
let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?;
|
||||
let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, 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)?;
|
||||
|
|
@ -391,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(ptr, dest)?;
|
||||
}
|
||||
"__rust_dealloc" => {
|
||||
let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?;
|
||||
let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, 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)?;
|
||||
|
|
@ -404,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
)?;
|
||||
}
|
||||
"__rust_realloc" => {
|
||||
let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?;
|
||||
let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, 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)?;
|
||||
|
|
@ -424,7 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// C memory handling functions
|
||||
"memcmp" => {
|
||||
let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?);
|
||||
|
|
@ -444,7 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"memrchr" => {
|
||||
let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -462,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
}
|
||||
"memchr" => {
|
||||
let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -479,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
}
|
||||
"strlen" => {
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -495,10 +496,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "asinf"
|
||||
| "atanf"
|
||||
=> {
|
||||
let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
// FIXME: Using host floats.
|
||||
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
|
||||
let f = match link_name {
|
||||
let f = match shim_name {
|
||||
"cbrtf" => f.cbrt(),
|
||||
"coshf" => f.cosh(),
|
||||
"sinhf" => f.sinh(),
|
||||
|
|
@ -515,13 +516,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "hypotf"
|
||||
| "atan2f"
|
||||
=> {
|
||||
let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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.
|
||||
let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?);
|
||||
let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?);
|
||||
let n = match link_name {
|
||||
let n = match shim_name {
|
||||
"_hypotf" | "hypotf" => f1.hypot(f2),
|
||||
"atan2f" => f1.atan2(f2),
|
||||
_ => bug!(),
|
||||
|
|
@ -537,10 +538,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "asin"
|
||||
| "atan"
|
||||
=> {
|
||||
let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
// FIXME: Using host floats.
|
||||
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
|
||||
let f = match link_name {
|
||||
let f = match shim_name {
|
||||
"cbrt" => f.cbrt(),
|
||||
"cosh" => f.cosh(),
|
||||
"sinh" => f.sinh(),
|
||||
|
|
@ -557,11 +558,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "hypot"
|
||||
| "atan2"
|
||||
=> {
|
||||
let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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()?);
|
||||
let n = match link_name {
|
||||
let n = match shim_name {
|
||||
"_hypot" | "hypot" => f1.hypot(f2),
|
||||
"atan2" => f1.atan2(f2),
|
||||
_ => bug!(),
|
||||
|
|
@ -573,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "ldexp"
|
||||
| "scalbn"
|
||||
=> {
|
||||
let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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()?;
|
||||
|
|
@ -594,11 +595,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Architecture-specific shims
|
||||
"llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.yield_active_thread();
|
||||
}
|
||||
"llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => {
|
||||
let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let arg = this.read_scalar(arg)?.to_i32()?;
|
||||
match arg {
|
||||
15 => { // SY ("full system scope")
|
||||
|
|
@ -612,8 +613,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// 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, 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),
|
||||
"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),
|
||||
target => throw_unsup_format!("the target `{}` is not supported", target),
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_target::abi::{Align, LayoutOf, Size};
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::strip_linker_suffix;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
use shims::posix::fs::EvalContextExt as _;
|
||||
use shims::posix::sync::EvalContextExt as _;
|
||||
|
|
@ -15,8 +16,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
|
|||
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,
|
||||
link_name: Symbol,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
|
|
@ -24,50 +24,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
) -> InterpResult<'tcx, EmulateByNameResult> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match link_name {
|
||||
match strip_linker_suffix(&link_name.as_str()) {
|
||||
// Environment related shims
|
||||
"getenv" => {
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.getenv(name)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"unsetenv" => {
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.unsetenv(name)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"setenv" => {
|
||||
let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(overwrite)?.to_i32()?;
|
||||
let result = this.setenv(name, value)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"getcwd" => {
|
||||
let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.getcwd(buf, size)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"chdir" => {
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.chdir(path)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// File related shims
|
||||
"open" | "open64" => {
|
||||
let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.open(path, flag, mode)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"fcntl" => {
|
||||
// `fcntl` is variadic. The argument count is checked based on the first argument
|
||||
// in `this.fcntl()`, so we do not use `check_shim` here.
|
||||
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?;
|
||||
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
|
||||
let result = this.fcntl(args)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"read" => {
|
||||
let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
|
||||
}
|
||||
"write" => {
|
||||
let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -85,60 +85,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
|
||||
}
|
||||
"unlink" => {
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.unlink(path)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"symlink" => {
|
||||
let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.symlink(target, linkpath)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"rename" => {
|
||||
let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.rename(oldpath, newpath)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"mkdir" => {
|
||||
let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.mkdir(path, mode)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"rmdir" => {
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.rmdir(path)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"closedir" => {
|
||||
let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.closedir(dirp)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"lseek" | "lseek64" => {
|
||||
let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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" => {
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.fsync(fd)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"fdatasync" => {
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.fdatasync(fd)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"readlink" => {
|
||||
let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.readlink(pathname, buf, bufsize)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
|
||||
}
|
||||
|
||||
// Allocation
|
||||
"posix_memalign" => {
|
||||
let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Dynamic symbol loading
|
||||
"dlsym" => {
|
||||
let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -182,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Querying system information
|
||||
"sysconf" => {
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let name = this.read_scalar(name)?.to_i32()?;
|
||||
|
||||
let sysconfs = &[
|
||||
|
|
@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Thread-local storage
|
||||
"pthread_key_create" => {
|
||||
let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let key_place = this.deref_operand(key)?;
|
||||
let dtor = this.read_scalar(dtor)?.check_init()?;
|
||||
|
||||
|
|
@ -235,21 +235,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
"pthread_key_delete" => {
|
||||
let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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" => {
|
||||
let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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" => {
|
||||
let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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()?;
|
||||
|
|
@ -261,149 +261,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Synchronization primitives
|
||||
"pthread_mutexattr_init" => {
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutexattr_init(attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutexattr_settype" => {
|
||||
let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutexattr_settype(attr, kind)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutexattr_destroy" => {
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutexattr_destroy(attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutex_init" => {
|
||||
let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutex_init(mutex, attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutex_lock" => {
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutex_lock(mutex)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutex_trylock" => {
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutex_trylock(mutex)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutex_unlock" => {
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutex_unlock(mutex)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_mutex_destroy" => {
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_mutex_destroy(mutex)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_rdlock" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_rdlock(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_tryrdlock" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_tryrdlock(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_wrlock" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_wrlock(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_trywrlock" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_trywrlock(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_unlock" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_unlock(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_rwlock_destroy" => {
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_rwlock_destroy(rwlock)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_condattr_init" => {
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_condattr_init(attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_condattr_destroy" => {
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_condattr_destroy(attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_cond_init" => {
|
||||
let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_cond_init(cond, attr)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_cond_signal" => {
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_cond_signal(cond)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_cond_broadcast" => {
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_cond_broadcast(cond)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_cond_wait" => {
|
||||
let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_cond_wait(cond, mutex)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_cond_timedwait" => {
|
||||
let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
|
||||
}
|
||||
"pthread_cond_destroy" => {
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_cond_destroy(cond)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// Threading
|
||||
"pthread_create" => {
|
||||
let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_create(thread, attr, start, arg)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_join" => {
|
||||
let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_join(thread, retval)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_detach" => {
|
||||
let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_detach(thread)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_self" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.pthread_self(dest)?;
|
||||
}
|
||||
"sched_yield" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.sched_yield()?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"nanosleep" => {
|
||||
let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.nanosleep(req, rem)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
"isatty" => {
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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.
|
||||
|
|
@ -412,7 +412,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
"pthread_atfork" => {
|
||||
let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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())?;
|
||||
|
|
@ -424,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// These shims are enabled only when the caller is in the standard library.
|
||||
"pthread_attr_getguardsize"
|
||||
if this.frame_in_std() => {
|
||||
let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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())?;
|
||||
|
|
@ -436,33 +436,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
| "pthread_attr_init"
|
||||
| "pthread_attr_destroy"
|
||||
if this.frame_in_std() => {
|
||||
let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
| "pthread_attr_setstacksize"
|
||||
if this.frame_in_std() => {
|
||||
let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
|
||||
| "signal"
|
||||
| "sigaltstack"
|
||||
if this.frame_in_std() => {
|
||||
let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
| "sigaction"
|
||||
| "mprotect"
|
||||
if this.frame_in_std() => {
|
||||
let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, 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, 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),
|
||||
"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),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_span::Symbol;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::strip_linker_suffix;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
use shims::posix::fs::EvalContextExt as _;
|
||||
use shims::posix::linux::sync::futex;
|
||||
|
|
@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
|
|||
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,
|
||||
link_name: Symbol,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
|
|
@ -22,10 +22,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
) -> InterpResult<'tcx, EmulateByNameResult> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match link_name {
|
||||
match strip_linker_suffix(&link_name.as_str()) {
|
||||
// errno
|
||||
"__errno_location" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let errno_place = this.last_error_place()?;
|
||||
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
|
||||
}
|
||||
|
|
@ -34,33 +34,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// These symbols have different names on Linux and macOS, which is the only reason they are not
|
||||
// in the `posix` module.
|
||||
"close" => {
|
||||
let &[ref fd] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.close(fd)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"opendir" => {
|
||||
let &[ref name] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.opendir(name)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir64_r" => {
|
||||
let &[ref dirp, ref entry, ref result] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.linux_readdir64_r(dirp, entry, result)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"ftruncate64" => {
|
||||
let &[ref fd, ref length] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.ftruncate64(fd, length)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
// Linux-only
|
||||
"posix_fadvise" => {
|
||||
let &[ref fd, ref offset, ref len, ref advice] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(fd)?.to_i32()?;
|
||||
this.read_scalar(offset)?.to_machine_isize(this)?;
|
||||
this.read_scalar(len)?.to_machine_isize(this)?;
|
||||
|
|
@ -70,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"sync_file_range" => {
|
||||
let &[ref fd, ref offset, ref nbytes, ref flags] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
|
@ -79,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"clock_gettime" => {
|
||||
// This is a POSIX function but it has only been tested on linux.
|
||||
let &[ref clk_id, ref tp] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.clock_gettime(clk_id, tp)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
|
@ -88,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"pthread_attr_getstack" => {
|
||||
// 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] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.deref_operand(attr_place)?;
|
||||
let addr_place = this.deref_operand(addr_place)?;
|
||||
let size_place = this.deref_operand(size_place)?;
|
||||
|
|
@ -109,19 +108,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Threading
|
||||
"prctl" => {
|
||||
let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.prctl(option, arg2, arg3, arg4, arg5)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_condattr_setclock" => {
|
||||
let &[ref attr, ref clock_id] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_condattr_setclock(attr, clock_id)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_condattr_getclock" => {
|
||||
let &[ref attr, ref clock_id] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.pthread_condattr_getclock(attr, clock_id)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
|
@ -130,7 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"syscall" => {
|
||||
// We do not use `check_shim` here because `syscall` is variadic. The argument
|
||||
// count is checked bellow.
|
||||
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?;
|
||||
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
|
||||
// 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.
|
||||
|
|
@ -195,12 +194,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Miscelanneous
|
||||
"getrandom" => {
|
||||
let &[ref ptr, ref len, ref flags] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
getrandom(this, ptr, len, flags, dest)?;
|
||||
}
|
||||
"sched_getaffinity" => {
|
||||
let &[ref pid, ref cpusetsize, ref mask] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(pid)?.to_i32()?;
|
||||
this.read_scalar(cpusetsize)?.to_machine_usize(this)?;
|
||||
this.deref_operand(mask)?;
|
||||
|
|
@ -214,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// These shims are enabled only when the caller is in the standard library.
|
||||
"pthread_getattr_np" if this.frame_in_std() => {
|
||||
let &[ref _thread, ref _attr] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_span::Symbol;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::strip_linker_suffix;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
use shims::posix::fs::EvalContextExt as _;
|
||||
use shims::posix::thread::EvalContextExt as _;
|
||||
|
|
@ -11,8 +12,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
|
|||
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,
|
||||
link_name: Symbol,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
|
|
@ -20,10 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
) -> InterpResult<'tcx, EmulateByNameResult> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match link_name {
|
||||
match strip_linker_suffix(&link_name.as_str()) {
|
||||
// errno
|
||||
"__error" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let errno_place = this.last_error_place()?;
|
||||
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
|
||||
}
|
||||
|
|
@ -31,87 +31,87 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// File related shims
|
||||
"close" | "close$NOCANCEL" => {
|
||||
let &[ref result] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.close(result)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"stat" | "stat$INODE64" => {
|
||||
let &[ref path, ref buf] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.macos_stat(path, buf)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"lstat" | "lstat$INODE64" => {
|
||||
let &[ref path, ref buf] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.macos_lstat(path, buf)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"fstat" | "fstat$INODE64" => {
|
||||
let &[ref fd, ref buf] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.macos_fstat(fd, buf)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"opendir" | "opendir$INODE64" => {
|
||||
let &[ref name] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.opendir(name)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir_r" | "readdir_r$INODE64" => {
|
||||
let &[ref dirp, ref entry, ref result] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.macos_readdir_r(dirp, entry, result)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"ftruncate" => {
|
||||
let &[ref fd, ref length] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.ftruncate64(fd, length)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// Environment related shims
|
||||
"_NSGetEnviron" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?;
|
||||
}
|
||||
|
||||
// Time related shims
|
||||
"gettimeofday" => {
|
||||
let &[ref tv, ref tz] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.gettimeofday(tv, tz)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"mach_absolute_time" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.mach_absolute_time()?;
|
||||
this.write_scalar(Scalar::from_u64(result), dest)?;
|
||||
}
|
||||
|
||||
"mach_timebase_info" => {
|
||||
let &[ref info] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.mach_timebase_info(info)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// Access to command-line arguments
|
||||
"_NSGetArgc" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?;
|
||||
}
|
||||
"_NSGetArgv" => {
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?;
|
||||
}
|
||||
|
||||
// Thread-local storage
|
||||
"_tlv_atexit" => {
|
||||
let &[ref dtor, ref data] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, 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()?;
|
||||
|
|
@ -122,14 +122,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Querying system information
|
||||
"pthread_get_stackaddr_np" => {
|
||||
let &[ref thread] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, 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" => {
|
||||
let &[ref thread] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Threading
|
||||
"pthread_setname_np" => {
|
||||
let &[ref name] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let name = this.read_scalar(name)?.check_init()?;
|
||||
this.pthread_setname_np(name)?;
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"mmap" if this.frame_in_std() => {
|
||||
// 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, _, _, _, _, _] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let addr = this.read_scalar(addr)?.check_init()?;
|
||||
this.write_scalar(addr, dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_target::abi::Size;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::strip_linker_suffix;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
use shims::windows::sync::EvalContextExt as _;
|
||||
|
||||
|
|
@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
|
|||
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,
|
||||
link_name: Symbol,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
|
|
@ -27,41 +27,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// DWORD = ULONG = u32
|
||||
// BOOL = i32
|
||||
// BOOLEAN = u8
|
||||
match link_name {
|
||||
match strip_linker_suffix(&link_name.as_str()) {
|
||||
// Environment related shims
|
||||
"GetEnvironmentVariableW" => {
|
||||
let &[ref name, ref buf, ref size] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.GetEnvironmentVariableW(name, buf, size)?;
|
||||
this.write_scalar(Scalar::from_u32(result), dest)?;
|
||||
}
|
||||
"SetEnvironmentVariableW" => {
|
||||
let &[ref name, ref value] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.SetEnvironmentVariableW(name, value)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"GetEnvironmentStringsW" => {
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.GetEnvironmentStringsW()?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"FreeEnvironmentStringsW" => {
|
||||
let &[ref env_block] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.FreeEnvironmentStringsW(env_block)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"GetCurrentDirectoryW" => {
|
||||
let &[ref size, ref buf] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.GetCurrentDirectoryW(size, buf)?;
|
||||
this.write_scalar(Scalar::from_u32(result), dest)?;
|
||||
}
|
||||
"SetCurrentDirectoryW" => {
|
||||
let &[ref path] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.SetCurrentDirectoryW(path)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
|
@ -69,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// File related shims
|
||||
"GetStdHandle" => {
|
||||
let &[ref which] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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.
|
||||
|
|
@ -77,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"WriteFile" => {
|
||||
let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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()?;
|
||||
|
|
@ -112,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Allocation
|
||||
"HeapAlloc" => {
|
||||
let &[ref handle, ref flags, ref size] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -122,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"HeapFree" => {
|
||||
let &[ref handle, ref flags, ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(handle)?.to_machine_isize(this)?;
|
||||
this.read_scalar(flags)?.to_u32()?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
|
|
@ -131,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"HeapReAlloc" => {
|
||||
let &[ref handle, ref flags, ref ptr, ref size] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(handle)?.to_machine_isize(this)?;
|
||||
this.read_scalar(flags)?.to_u32()?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
|
|
@ -143,13 +142,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// errno
|
||||
"SetLastError" => {
|
||||
let &[ref error] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let error = this.read_scalar(error)?.check_init()?;
|
||||
this.set_last_error(error)?;
|
||||
}
|
||||
"GetLastError" => {
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let last_error = this.get_last_error()?;
|
||||
this.write_scalar(last_error, dest)?;
|
||||
}
|
||||
|
|
@ -157,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Querying system information
|
||||
"GetSystemInfo" => {
|
||||
let &[ref system_info] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let system_info = this.deref_operand(system_info)?;
|
||||
// Initialize with `0`.
|
||||
this.memory.write_bytes(
|
||||
|
|
@ -175,14 +173,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// This just creates a key; Windows does not natively support TLS destructors.
|
||||
|
||||
// Create key and return it.
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, 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" => {
|
||||
let &[ref key] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -190,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"TlsSetValue" => {
|
||||
let &[ref key, ref new_ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// Access to command-line arguments
|
||||
"GetCommandLineW" => {
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.write_scalar(
|
||||
this.machine.cmd_line.expect("machine must be initialized"),
|
||||
dest,
|
||||
|
|
@ -214,20 +210,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"GetSystemTimeAsFileTime" => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref LPFILETIME] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.GetSystemTimeAsFileTime(LPFILETIME)?;
|
||||
}
|
||||
"QueryPerformanceCounter" => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref lpPerformanceCount] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"QueryPerformanceFrequency" => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref lpFrequency] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let result = this.QueryPerformanceFrequency(lpFrequency)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
|
@ -235,33 +231,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Synchronization primitives
|
||||
"AcquireSRWLockExclusive" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.AcquireSRWLockExclusive(ptr)?;
|
||||
}
|
||||
"ReleaseSRWLockExclusive" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.ReleaseSRWLockExclusive(ptr)?;
|
||||
}
|
||||
"TryAcquireSRWLockExclusive" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let ret = this.TryAcquireSRWLockExclusive(ptr)?;
|
||||
this.write_scalar(Scalar::from_u8(ret), dest)?;
|
||||
}
|
||||
"AcquireSRWLockShared" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.AcquireSRWLockShared(ptr)?;
|
||||
}
|
||||
"ReleaseSRWLockShared" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.ReleaseSRWLockShared(ptr)?;
|
||||
}
|
||||
"TryAcquireSRWLockShared" => {
|
||||
let &[ref ptr] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let ret = this.TryAcquireSRWLockShared(ptr)?;
|
||||
this.write_scalar(Scalar::from_u8(ret), dest)?;
|
||||
}
|
||||
|
|
@ -270,7 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"GetProcAddress" => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref hModule, ref lpProcName] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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)? {
|
||||
|
|
@ -285,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"SystemFunction036" => {
|
||||
// This is really 'RtlGenRandom'.
|
||||
let &[ref ptr, ref len] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
let len = this.read_scalar(len)?.to_u32()?;
|
||||
this.gen_random(ptr, len.into())?;
|
||||
|
|
@ -293,7 +289,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
"BCryptGenRandom" => {
|
||||
let &[ref algorithm, ref ptr, ref len, ref flags] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
let algorithm = this.read_scalar(algorithm)?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
let len = this.read_scalar(len)?.to_u32()?;
|
||||
|
|
@ -315,7 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"GetConsoleScreenBufferInfo" => {
|
||||
// `term` needs this, so we fake it.
|
||||
let &[ref console, ref buffer_info] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(console)?.to_machine_isize(this)?;
|
||||
this.deref_operand(buffer_info)?;
|
||||
// Indicate an error.
|
||||
|
|
@ -325,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"GetConsoleMode" => {
|
||||
// Windows "isatty" (in libtest) needs this, so we fake it.
|
||||
let &[ref console, ref mode] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
this.read_scalar(console)?.to_machine_isize(this)?;
|
||||
this.deref_operand(mode)?;
|
||||
// Indicate an error.
|
||||
|
|
@ -333,8 +329,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
"SwitchToThread" => {
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, 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)?;
|
||||
|
|
@ -343,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// Better error for attempts to create a thread
|
||||
"CreateThread" => {
|
||||
let &[_, _, _, _, _, _] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
|
||||
this.handle_unsupported("can't create threads on Windows")?;
|
||||
return Ok(EmulateByNameResult::AlreadyJumped);
|
||||
|
|
@ -352,29 +347,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// 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() => {
|
||||
let &[] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
// Just fake a HANDLE
|
||||
this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
|
||||
}
|
||||
"SetConsoleTextAttribute" if this.frame_in_std() => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref _hConsoleOutput, ref _wAttribute] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
// Pretend these does not exist / nothing happened, by returning zero.
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
"AddVectoredExceptionHandler" if this.frame_in_std() => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref _First, ref _Handler] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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() => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[_StackSizeInBytes] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, 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)?;
|
||||
}
|
||||
|
|
@ -386,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
{
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref _lpCriticalSection] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
assert_eq!(
|
||||
this.get_total_thread_count(),
|
||||
1,
|
||||
|
|
@ -399,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"TryEnterCriticalSection" if this.frame_in_std() => {
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref _lpCriticalSection] =
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?;
|
||||
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||
assert_eq!(
|
||||
this.get_total_thread_count(),
|
||||
1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue