refactor dlsym: dispatch symbols via the normal shim mechanism

This commit is contained in:
Ralf Jung 2023-10-06 09:15:48 +02:00
parent f9003c08ab
commit bc8d4dfa95
24 changed files with 168 additions and 461 deletions

View file

@ -960,7 +960,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
self.check_abi(abi, exp_abi)?;
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
// We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased
// We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
// performance. Note that this means we won't catch any undefined behavior in
// compiler-builtins when running other crates, but Miri can still be run on
// compiler-builtins itself (or any crate that uses it as a normal dependency)

View file

@ -8,6 +8,7 @@
#![feature(yeet_expr)]
#![feature(nonzero_ops)]
#![feature(round_ties_even)]
#![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(trait_upcasting)]
// Configure clippy and other lints
@ -86,9 +87,8 @@ pub use rustc_const_eval::interpret::*;
// Resolve ambiguity.
pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _};
pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _};
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
pub use crate::shims::foreign_items::EvalContextExt as _;
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
pub use crate::shims::intrinsics::EvalContextExt as _;
pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};

View file

@ -709,9 +709,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
"android" => {
// "signal"
let layout = this.machine.layouts.const_raw_ptr;
let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)?
.expect("`signal` must be an actual dlsym on android");
let ptr = this.fn_ptr(FnVal::Other(dlsym));
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
Self::alloc_extern_static(this, "signal", val)?;
// A couple zero-initialized pointer-sized extern statics.
@ -867,7 +865,7 @@ impl<'mir, 'tcx> MiriInterpCxExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {
/// Machine hook implementations.
impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
type MemoryKind = MiriMemoryKind;
type ExtraFnVal = Dlsym;
type ExtraFnVal = DynSym;
type FrameExtra = FrameExtra<'tcx>;
type AllocExtra = AllocExtra<'tcx>;
@ -939,15 +937,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
#[inline(always)]
fn call_extra_fn(
ecx: &mut MiriInterpCx<'mir, 'tcx>,
fn_val: Dlsym,
fn_val: DynSym,
abi: Abi,
args: &[FnArg<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
_unwind: mir::UnwindAction,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
ecx.call_dlsym(fn_val, abi, &args, dest, ret)
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
}
#[inline(always)]

View file

@ -1,48 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use crate::helpers::target_os_is_unix;
use crate::*;
use shims::unix::dlsym as unix;
use shims::windows::dlsym as windows;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
Posix(unix::Dlsym),
Windows(windows::Dlsym),
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
let name = &*String::from_utf8_lossy(name);
Ok(match target_os {
target if target_os_is_unix(target) =>
unix::Dlsym::from_str(name, target)?.map(Dlsym::Posix),
"windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows),
os => bug!("dlsym not implemented for target_os {}", os),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
match dlsym {
Dlsym::Posix(dlsym) =>
unix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret),
Dlsym::Windows(dlsym) =>
windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret),
}
}
}

View file

@ -6,7 +6,7 @@ use rustc_apfloat::Float;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_hir::{
def::DefKind,
def_id::{CrateNum, DefId, LOCAL_CRATE},
def_id::{CrateNum, LOCAL_CRATE},
};
use rustc_middle::middle::{
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
@ -25,7 +25,18 @@ use super::backtrace::EvalContextExt as _;
use crate::helpers::target_os_is_unix;
use crate::*;
/// Returned by `emulate_foreign_item_by_name`.
/// Type of dynamic symbols (for `dlsym` et al)
#[derive(Debug, Copy, Clone)]
pub struct DynSym(Symbol);
#[allow(clippy::should_implement_trait)]
impl DynSym {
pub fn from_str(name: &str) -> Self {
DynSym(Symbol::intern(name))
}
}
/// Returned by `emulate_foreign_item_inner`.
pub enum EmulateByNameResult<'mir, 'tcx> {
/// The caller is expected to jump to the return block.
NeedsJumping,
@ -254,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// is delegated to another function.
fn emulate_foreign_item(
&mut self,
def_id: DefId,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
@ -262,7 +273,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
let this = self.eval_context_mut();
let link_name = this.item_link_name(def_id);
let tcx = this.tcx.tcx;
// First: functions that diverge.
@ -322,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
};
// Second: functions that return immediately.
match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? {
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
EmulateByNameResult::NeedsJumping => {
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
@ -345,6 +355,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(None)
}
/// Emulates a call to a `DynSym`.
fn emulate_dyn_sym(
&mut self,
sym: DynSym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?;
assert!(res.is_none(), "DynSyms that delegate are not supported");
Ok(())
}
/// Emulates calling the internal __rust_* allocator functions
fn emulate_allocator(
&mut self,
@ -373,8 +398,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
/// Emulates calling a foreign item using its name.
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
@ -1045,11 +1069,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ =>
return match this.tcx.sess.target.os.as_ref() {
target_os if target_os_is_unix(target_os) =>
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest,
),
"windows" =>
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest,
),
_ => Ok(EmulateByNameResult::NotSupported),

View file

@ -9,7 +9,6 @@ pub mod unix;
pub mod windows;
mod x86;
pub mod dlsym;
pub mod env;
pub mod os_str;
pub mod panic;
@ -58,7 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// foreign function
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
return this.emulate_foreign_item(instance.def_id(), abi, &args, dest, ret, unwind);
let link_name = this.item_link_name(instance.def_id());
return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
}
// Otherwise, load the MIR.

View file

@ -1,54 +0,0 @@
use rustc_middle::mir;
use crate::helpers::check_arg_count;
use crate::*;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
signal,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"signal" => Some(Dlsym::signal),
"android_set_abort_message" => None,
_ => throw_unsup_format!("unsupported Android dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "android");
match dlsym {
Dlsym::signal => {
if !this.frame_in_std() {
throw_unsup_format!(
"`signal` support is crude and just enough for libstd to work"
);
}
let [_sig, _func] = check_arg_count(args)?;
this.write_null(dest)?;
}
}
log::trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View file

@ -6,17 +6,26 @@ use shims::foreign_items::EmulateByNameResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "signal")
}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
_abi: Abi,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let _this = self.eval_context_mut();
#[allow(clippy::match_single_binding)]
let this = self.eval_context_mut();
match link_name.as_str() {
"signal" if this.frame_in_std() => {
let [_sig, _func] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.write_null(dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),
}

View file

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View file

@ -1,55 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::unix::android::dlsym as android;
use shims::unix::freebsd::dlsym as freebsd;
use shims::unix::linux::dlsym as linux;
use shims::unix::macos::dlsym as macos;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
Android(android::Dlsym),
FreeBsd(freebsd::Dlsym),
Linux(linux::Dlsym),
MacOs(macos::Dlsym),
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match target_os {
"android" => android::Dlsym::from_str(name)?.map(Dlsym::Android),
"freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd),
"linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux),
"macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs),
_ => panic!("unsupported Unix OS {target_os}"),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
this.check_abi(abi, Abi::C { unwind: false })?;
match dlsym {
Dlsym::Android(dlsym) =>
android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::FreeBsd(dlsym) =>
freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
}
}
}

View file

@ -1,4 +1,5 @@
use std::ffi::OsStr;
use std::str;
use log::trace;
@ -14,9 +15,14 @@ use shims::unix::mem::EvalContextExt as _;
use shims::unix::sync::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
use shims::unix::android::foreign_items as android;
use shims::unix::freebsd::foreign_items as freebsd;
use shims::unix::linux::foreign_items as linux;
use shims::unix::macos::foreign_items as macos;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
@ -25,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
#[rustfmt::skip]
match link_name.as_str() {
// Environment related shims
@ -230,9 +236,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.read_target_usize(handle)?;
let symbol = this.read_pointer(symbol)?;
let symbol_name = this.read_c_str(symbol)?;
if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
let ptr = this.fn_ptr(FnVal::Other(dlsym));
let name = this.read_c_str(symbol)?;
let is_dyn_sym = |name| match &*this.tcx.sess.target.os {
"android" => android::is_dyn_sym(name),
"freebsd" => freebsd::is_dyn_sym(name),
"linux" => linux::is_dyn_sym(name),
"macos" => macos::is_dyn_sym(name),
target_os => panic!("unsupported Unix OS {target_os}"),
};
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) {
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
this.write_pointer(ptr, dest)?;
} else {
this.write_null(dest)?;
@ -609,10 +622,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => {
let target_os = &*this.tcx.sess.target.os;
return match target_os {
"android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
_ => Ok(EmulateByNameResult::NotSupported),
};
}

View file

@ -1,36 +0,0 @@
use rustc_middle::mir;
use crate::*;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
throw_unsup_format!("unsupported FreeBSD dlsym: {}", name)
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let _ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "freebsd");
match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
}
}

View file

@ -5,10 +5,13 @@ use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::unix::thread::EvalContextExt as _;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,

View file

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View file

@ -1,40 +0,0 @@
use rustc_middle::mir;
use crate::*;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"__pthread_get_minstack" => None,
"getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL.
"statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL.
_ => throw_unsup_format!("unsupported Linux dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
_args: &[OpTy<'tcx, Provenance>],
_dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let _ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "linux");
match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
}
}

View file

@ -12,9 +12,13 @@ use shims::unix::linux::sync::futex;
use shims::unix::sync::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
@ -23,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
match link_name.as_str() {
// errno

View file

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod fd;
pub mod foreign_items;
pub mod mem;

View file

@ -1,51 +0,0 @@
use rustc_middle::mir;
use log::trace;
use super::foreign_items::EvalContextExt as _;
use crate::*;
use helpers::check_arg_count;
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
getentropy,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"getentropy" => Some(Dlsym::getentropy),
_ => throw_unsup_format!("unsupported macOS dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "macos");
match dlsym {
Dlsym::getentropy => {
let [ptr, len] = check_arg_count(args)?;
let result = this.getentropy(ptr, len)?;
this.write_scalar(result, dest)?;
}
}
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View file

@ -6,9 +6,13 @@ use shims::foreign_items::EmulateByNameResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "getentropy")
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
@ -17,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
match link_name.as_str() {
// errno
@ -113,8 +117,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"getentropy" => {
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.getentropy(buf, bufsize)?;
this.write_scalar(result, dest)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
}
// Access to command-line arguments
@ -206,19 +214,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(EmulateByNameResult::NeedsJumping)
}
fn getentropy(
&mut self,
buffer_op: &OpTy<'tcx, Provenance>,
length_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "getentropy");
let ptr = this.read_pointer(buffer_op)?;
let len = this.read_target_usize(length_op)?;
this.gen_random(ptr, len)?;
Ok(Scalar::from_i32(0)) // KERN_SUCCESS
}
}

View file

@ -1,2 +1 @@
pub mod dlsym;
pub mod foreign_items;

View file

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod foreign_items;
mod fs;

View file

@ -1,82 +0,0 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;
use log::trace;
use crate::helpers::check_arg_count;
use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
use crate::shims::windows::sync::EvalContextExt as _;
use crate::*;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
SetThreadDescription,
WaitOnAddress,
WakeByAddressSingle,
}
impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match name {
"GetSystemTimePreciseAsFileTime" => None,
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
"WaitOnAddress" => Some(Dlsym::WaitOnAddress),
"WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
_ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
})
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let ret = ret.expect("we don't support any diverging dlsym");
assert!(this.tcx.sess.target.os == "windows");
this.check_abi(abi, Abi::System { unwind: false })?;
match dlsym {
Dlsym::SetThreadDescription => {
let [handle, name] = check_arg_count(args)?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
let thread = match Handle::from_scalar(handle, this)? {
Some(Handle::Thread(thread)) => thread,
Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(),
_ => this.invalid_handle("SetThreadDescription")?,
};
this.set_thread_name_wide(thread, &name);
this.write_null(dest)?;
}
Dlsym::WaitOnAddress => {
let [ptr_op, compare_op, size_op, timeout_op] = check_arg_count(args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
Dlsym::WakeByAddressSingle => {
let [ptr_op] = check_arg_count(args)?;
this.WakeByAddressSingle(ptr_op)?;
}
}
trace!("{:?}", this.dump_place(dest));
this.go_to_block(ret);
Ok(())
}
}

View file

@ -1,4 +1,5 @@
use std::iter;
use std::str;
use rustc_span::Symbol;
use rustc_target::abi::Size;
@ -10,9 +11,13 @@ use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
use shims::windows::sync::EvalContextExt as _;
use shims::windows::thread::EvalContextExt as _;
fn is_dyn_sym(name: &str) -> bool {
matches!(name, "SetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle")
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
@ -21,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
// See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
// Windows API stubs.
// HANDLE = isize
@ -326,6 +331,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.WakeAllConditionVariable(condvar)?;
}
"WaitOnAddress" => {
let [ptr_op, compare_op, size_op, timeout_op] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
"WakeByAddressSingle" => {
let [ptr_op] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.WakeByAddressSingle(ptr_op)?;
}
// Dynamic symbol loading
"GetProcAddress" => {
@ -334,14 +351,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.read_target_isize(hModule)?;
let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
let ptr = this.fn_ptr(FnVal::Other(dlsym));
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) {
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
this.write_pointer(ptr, dest)?;
} else {
this.write_null(dest)?;
}
}
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(Scalar::from_u32(ret), dest)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
dest,
)?;
}
"SetThreadDescription" => {
let [handle, name] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
let thread = match Handle::from_scalar(handle, this)? {
Some(Handle::Thread(thread)) => thread,
Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(),
_ => this.invalid_handle("SetThreadDescription")?,
};
this.set_thread_name_wide(thread, &name);
this.write_null(dest)?;
}
// Miscellaneous
"SystemFunction036" => {
// This is really 'RtlGenRandom'.
@ -456,32 +517,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(Scalar::from_u32(ret), dest)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
dest,
)?;
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"GetProcessHeap" if this.frame_in_std() => {

View file

@ -1,4 +1,3 @@
pub mod dlsym;
pub mod foreign_items;
mod handle;