Auto merge of #977 - christianpoveda:last-error-ptr, r=oli-obk

Move last error into memory

These changes move the `Evaluator::last_error` into miri's memory and implement the `__errno_location()` shim (which is used by the file handling functions when they fail).
This commit is contained in:
bors
2019-10-08 13:21:05 +00:00
5 changed files with 276 additions and 180 deletions
+44 -27
View File
@@ -3,16 +3,15 @@
use rand::rngs::StdRng;
use rand::SeedableRng;
use syntax::source_map::DUMMY_SP;
use rustc::ty::{self, TyCtxt};
use rustc::ty::layout::{LayoutOf, Size, Align};
use rustc::hir::def_id::DefId;
use rustc::ty::layout::{Align, LayoutOf, Size};
use rustc::ty::{self, TyCtxt};
use syntax::source_map::DUMMY_SP;
use crate::{
InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error,
Scalar, Tag, Pointer, FnVal,
MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt,
EnvVars,
struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError,
InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag,
TlsEvalContextExt,
};
/// Configuration needed to spawn a Miri instance.
@@ -40,7 +39,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(config.communicate),
MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
MemoryExtra::new(
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
config.validate,
),
);
// Complete initialization.
EnvVars::init(&mut ecx, config.excluded_env_vars);
@@ -50,9 +52,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
let main_mir = ecx.load_mir(main_instance.def, None)?;
if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
throw_unsup_format!(
"miri does not support main functions without `fn()` type signatures"
);
throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
}
let start_id = tcx.lang_items().start_fn().unwrap();
@@ -62,9 +62,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
ecx.tcx.tcx,
ty::ParamEnv::reveal_all(),
start_id,
ecx.tcx.mk_substs(
::std::iter::once(ty::subst::GenericArg::from(main_ret_ty)))
).unwrap();
ecx.tcx
.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
)
.unwrap();
let start_mir = ecx.load_mir(start_instance.def, None)?;
if start_mir.arg_count != 3 {
@@ -91,7 +92,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
let mut args = ecx.frame().body.args_iter();
// First argument: pointer to `main()`.
let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance));
let main_ptr = ecx
.memory_mut()
.create_fn_alloc(FnVal::Instance(main_instance));
let dest = ecx.local_place(args.next().unwrap())?;
ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
@@ -124,16 +127,23 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
// Add `0` terminator.
let mut arg = arg.into_bytes();
arg.push(0);
argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()));
argvs.push(
ecx.memory_mut()
.allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()),
);
}
// Make an array with all these pointers, in the Miri memory.
let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?;
let argvs_layout = ecx.layout_of(
ecx.tcx
.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64),
)?;
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
for (idx, arg) in argvs.into_iter().enumerate() {
let place = ecx.mplace_field(argvs_place, idx as u64)?;
ecx.write_scalar(Scalar::Ptr(arg), place.into())?;
}
ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
ecx.memory_mut()
.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
// Write a pointer to that place as the argument.
let argv = argvs_place.ptr;
ecx.write_scalar(argv, dest)?;
@@ -145,7 +155,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
}
// Store command line as UTF-16 for Windows `GetCommandLineW`.
{
let tcx = &{ecx.tcx.tcx};
let tcx = &{ ecx.tcx.tcx };
let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
let cmd_ptr = ecx.memory_mut().allocate(
Size::from_bytes(cmd_utf16.len() as u64 * 2),
@@ -168,16 +178,22 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
}
}
assert!(args.next().is_none(), "start lang item has more arguments than expected");
assert!(
args.next().is_none(),
"start lang item has more arguments than expected"
);
// Set the last_error to 0
let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?;
let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into());
ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?;
ecx.machine.last_error = errno_ptr;
Ok(ecx)
}
pub fn eval_main<'tcx>(
tcx: TyCtxt<'tcx>,
main_id: DefId,
config: MiriConfig,
) {
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
let mut ecx = match create_ecx(tcx, main_id, config) {
Ok(ecx) => ecx,
Err(mut err) => {
@@ -228,8 +244,9 @@ pub fn eval_main<'tcx>(
// We iterate with indices because we need to look at the next frame (the caller).
for idx in 0..frames.len() {
let frame_info = &frames[idx];
let call_site_is_local = frames.get(idx+1).map_or(false,
|caller_info| caller_info.instance.def_id().is_local());
let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
caller_info.instance.def_id().is_local()
});
if call_site_is_local {
err.span_note(frame_info.call_site, &frame_info.to_string());
} else {
+45 -26
View File
@@ -1,24 +1,28 @@
//! Global machine state as well as implementation of the interpreter engine
//! `Machine` trait.
use std::rc::Rc;
use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;
use rand::rngs::StdRng;
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{
self,
layout::{LayoutOf, Size},
Ty, TyCtxt,
};
use syntax::attr;
use syntax::symbol::sym;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, layout::{Size, LayoutOf}};
use rustc::mir;
use crate::*;
// Some global facts about the emulated machine.
pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture
pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever
pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture
pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever
pub const NUM_CPUS: u64 = 1;
/// Extra memory kinds
@@ -88,7 +92,7 @@ pub struct Evaluator<'tcx> {
pub(crate) cmd_line: Option<Pointer<Tag>>,
/// Last OS error.
pub(crate) last_error: u32,
pub(crate) last_error: Option<Pointer<Tag>>,
/// TLS state.
pub(crate) tls: TlsData<'tcx>,
@@ -109,7 +113,7 @@ pub(crate) fn new(communicate: bool) -> Self {
argc: None,
argv: None,
cmd_line: None,
last_error: 0,
last_error: None,
tls: TlsData::default(),
communicate,
file_handler: Default::default(),
@@ -146,7 +150,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
type PointerTag = Tag;
type ExtraFnVal = Dlsym;
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
type MemoryMap = MonoHashMap<
AllocId,
(
MemoryKind<MiriMemoryKind>,
Allocation<Tag, Self::AllocExtra>,
),
>;
const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Static);
@@ -264,8 +274,7 @@ fn find_foreign_static(
}
#[inline(always)]
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
{
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
// We are not interested in detecting loops.
Ok(())
}
@@ -275,7 +284,10 @@ fn tag_allocation<'b>(
id: AllocId,
alloc: Cow<'b, Allocation>,
kind: Option<MemoryKind<Self::MemoryKinds>>,
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
) -> (
Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>,
Self::PointerTag,
) {
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
let alloc = alloc.into_owned();
let (stacks, base_tag) = if !memory_extra.validate {
@@ -291,12 +303,14 @@ fn tag_allocation<'b>(
};
let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut();
let alloc: Allocation<Tag, Self::AllocExtra> = alloc.with_tags_and_extra(
|alloc| if !memory_extra.validate {
Tag::Untagged
} else {
// Only statics may already contain pointers at this point
assert_eq!(kind, MiriMemoryKind::Static.into());
stacked_borrows.static_base_ptr(alloc)
|alloc| {
if !memory_extra.validate {
Tag::Untagged
} else {
// Only statics may already contain pointers at this point
assert_eq!(kind, MiriMemoryKind::Static.into());
stacked_borrows.static_base_ptr(alloc)
}
},
AllocExtra {
stacked_borrows: stacks,
@@ -306,14 +320,14 @@ fn tag_allocation<'b>(
}
#[inline(always)]
fn tag_static_base_pointer(
memory_extra: &MemoryExtra,
id: AllocId,
) -> Self::PointerTag {
fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag {
if !memory_extra.validate {
Tag::Untagged
} else {
memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id)
memory_extra
.stacked_borrows
.borrow_mut()
.static_base_ptr(id)
}
}
@@ -325,7 +339,7 @@ fn retag(
) -> InterpResult<'tcx> {
if !Self::enforce_validity(ecx) {
// No tracking.
Ok(())
Ok(())
} else {
ecx.retag(kind, place)
}
@@ -343,7 +357,12 @@ fn stack_pop(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
extra: stacked_borrows::CallId,
) -> InterpResult<'tcx> {
Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra))
Ok(ecx
.memory()
.extra
.stacked_borrows
.borrow_mut()
.end_call(extra))
}
#[inline(always)]
+4 -6
View File
@@ -143,12 +143,10 @@ fn getcwd(
.write_bytes(tcx, buf, &bytes)?;
return Ok(Scalar::Ptr(buf));
}
this.machine.last_error = this
.eval_path_scalar(&["libc", "ERANGE"])?
.unwrap()
.to_u32()?;
let erange = this.eval_libc("ERANGE")?;
this.set_last_error(erange)?;
}
Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32,
Err(e) => this.consume_io_error(e)?,
}
Ok(Scalar::ptr_null(&*this.tcx))
}
@@ -172,7 +170,7 @@ fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
match env::set_current_dir(path) {
Ok(()) => Ok(0),
Err(e) => {
this.machine.last_error = e.raw_os_error().unwrap() as u32;
this.consume_io_error(e)?;
Ok(-1)
}
}
+178 -118
View File
@@ -1,9 +1,9 @@
use std::convert::TryInto;
use rustc_apfloat::Float;
use rustc::ty::layout::{Align, LayoutOf, Size};
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::layout::{Align, LayoutOf, Size};
use rustc_apfloat::Float;
use syntax::attr;
use syntax::symbol::sym;
@@ -40,42 +40,33 @@ fn prev_power_of_two(x: u64) -> u64 {
Align::from_bytes(prev_power_of_two(size)).unwrap()
}
fn malloc(
&mut self,
size: u64,
zero_init: bool,
kind: MiriMemoryKind,
) -> Scalar<Tag> {
fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar<Tag> {
let this = self.eval_context_mut();
let tcx = &{this.tcx.tcx};
let tcx = &{ this.tcx.tcx };
if size == 0 {
Scalar::from_int(0, this.pointer_size())
} else {
let align = this.min_align(size, kind);
let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, kind.into());
let ptr = this
.memory_mut()
.allocate(Size::from_bytes(size), align, kind.into());
if zero_init {
// We just allocated this, the access cannot fail
this.memory_mut()
.get_mut(ptr.alloc_id).unwrap()
.write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap();
.get_mut(ptr.alloc_id)
.unwrap()
.write_repeat(tcx, ptr, 0, Size::from_bytes(size))
.unwrap();
}
Scalar::Ptr(ptr)
}
}
fn free(
&mut self,
ptr: Scalar<Tag>,
kind: MiriMemoryKind,
) -> InterpResult<'tcx> {
fn free(&mut self, ptr: Scalar<Tag>, kind: MiriMemoryKind) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
if !this.is_null(ptr)? {
let ptr = this.force_ptr(ptr)?;
this.memory_mut().deallocate(
ptr,
None,
kind.into(),
)?;
this.memory_mut().deallocate(ptr, None, kind.into())?;
}
Ok(())
}
@@ -92,22 +83,16 @@ fn realloc(
if new_size == 0 {
Ok(Scalar::from_int(0, this.pointer_size()))
} else {
let new_ptr = this.memory_mut().allocate(
Size::from_bytes(new_size),
new_align,
kind.into()
);
let new_ptr =
this.memory_mut()
.allocate(Size::from_bytes(new_size), new_align, kind.into());
Ok(Scalar::Ptr(new_ptr))
}
} else {
let old_ptr = this.force_ptr(old_ptr)?;
let memory = this.memory_mut();
if new_size == 0 {
memory.deallocate(
old_ptr,
None,
kind.into(),
)?;
memory.deallocate(old_ptr, None, kind.into())?;
Ok(Scalar::from_int(0, this.pointer_size()))
} else {
let new_ptr = memory.reallocate(
@@ -139,7 +124,7 @@ fn emulate_foreign_item(
};
// Strip linker suffixes (seen on 32-bit macOS).
let link_name = link_name.trim_end_matches("$UNIX2003");
let tcx = &{this.tcx.tcx};
let tcx = &{ this.tcx.tcx };
// First: functions that diverge.
match link_name {
@@ -151,8 +136,10 @@ fn emulate_foreign_item(
let code = this.read_scalar(args[0])?.to_i32()?;
return Err(InterpError::Exit(code).into());
}
_ => if dest.is_none() {
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
_ => {
if dest.is_none() {
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
}
}
}
@@ -168,7 +155,9 @@ fn emulate_foreign_item(
"calloc" => {
let items = this.read_scalar(args[0])?.to_usize(this)?;
let len = this.read_scalar(args[1])?.to_usize(this)?;
let size = items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
let size = items
.checked_mul(len)
.ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C);
this.write_scalar(res, dest)?;
}
@@ -193,7 +182,7 @@ fn emulate_foreign_item(
let ptr = this.memory_mut().allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::C.into()
MiriMemoryKind::C.into(),
);
this.write_scalar(Scalar::Ptr(ptr), ret.into())?;
}
@@ -219,12 +208,11 @@ fn emulate_foreign_item(
if !align.is_power_of_two() {
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = this.memory_mut()
.allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into()
);
let ptr = this.memory_mut().allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into(),
);
this.write_scalar(Scalar::Ptr(ptr), dest)?;
}
"__rust_alloc_zeroed" => {
@@ -236,16 +224,17 @@ fn emulate_foreign_item(
if !align.is_power_of_two() {
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = this.memory_mut()
.allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into()
);
let ptr = this.memory_mut().allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into(),
);
// We just allocated this, the access cannot fail
this.memory_mut()
.get_mut(ptr.alloc_id).unwrap()
.write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap();
.get_mut(ptr.alloc_id)
.unwrap()
.write_repeat(tcx, ptr, 0, Size::from_bytes(size))
.unwrap();
this.write_scalar(Scalar::Ptr(ptr), dest)?;
}
"__rust_dealloc" => {
@@ -261,7 +250,10 @@ fn emulate_foreign_item(
let ptr = this.force_ptr(ptr)?;
this.memory_mut().deallocate(
ptr,
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
Some((
Size::from_bytes(old_size),
Align::from_bytes(align).unwrap(),
)),
MiriMemoryKind::Rust.into(),
)?;
}
@@ -288,7 +280,8 @@ fn emulate_foreign_item(
}
"syscall" => {
let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])?
let sys_getrandom = this
.eval_path_scalar(&["libc", "SYS_getrandom"])?
.expect("Failed to get libc::SYS_getrandom")
.to_usize(this)?;
@@ -300,9 +293,7 @@ fn emulate_foreign_item(
// so skip over it.
linux_getrandom(this, &args[1..], dest)?;
}
id => {
throw_unsup_format!("miri does not support syscall ID {}", id)
}
id => throw_unsup_format!("miri does not support syscall ID {}", id),
}
}
@@ -342,7 +333,8 @@ fn emulate_foreign_item(
// TODO: consider making this reusable? `InterpCx::step` does something similar
// for the TLS destructors, and of course `eval_main`.
let mir = this.load_mir(f_instance.def, None)?;
let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
let ret_place =
MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
this.push_stack_frame(
f_instance,
mir.span,
@@ -353,12 +345,16 @@ fn emulate_foreign_item(
)?;
let mut args = this.frame().body.args_iter();
let arg_local = args.next()
let arg_local = args
.next()
.expect("Argument to __rust_maybe_catch_panic does not take enough arguments.");
let arg_dest = this.local_place(arg_local)?;
this.write_scalar(data, arg_dest)?;
assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
assert!(
args.next().is_none(),
"__rust_maybe_catch_panic argument has more arguments than expected"
);
// We ourselves will return `0`, eventually (because we will not return if we paniced).
this.write_null(dest)?;
@@ -384,18 +380,19 @@ fn emulate_foreign_item(
}
};
this.write_scalar(
Scalar::from_int(result, Size::from_bits(32)),
dest,
)?;
this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?;
}
"memrchr" => {
let ptr = this.read_scalar(args[0])?.not_undef()?;
let val = this.read_scalar(args[1])?.to_i32()? as u8;
let num = this.read_scalar(args[2])?.to_usize(this)?;
if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
.iter().rev().position(|&c| c == val)
if let Some(idx) = this
.memory()
.read_bytes(ptr, Size::from_bytes(num))?
.iter()
.rev()
.position(|&c| c == val)
{
let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
this.write_scalar(new_ptr, dest)?;
@@ -421,6 +418,11 @@ fn emulate_foreign_item(
}
}
"__errno_location" => {
let errno_scalar: Scalar<Tag> = this.machine.last_error.unwrap().into();
this.write_scalar(errno_scalar, dest)?;
}
"getenv" => {
let result = this.getenv(args[0])?;
this.write_scalar(result, dest)?;
@@ -497,10 +499,7 @@ fn emulate_foreign_item(
this.write(args[0], args[1], args[2])?
};
// Now, `result` is the value we return back to the program.
this.write_scalar(
Scalar::from_int(result, dest.layout.size),
dest,
)?;
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}
"strlen" => {
@@ -510,8 +509,7 @@ fn emulate_foreign_item(
}
// math functions
"cbrtf" | "coshf" | "sinhf" |"tanf" => {
"cbrtf" | "coshf" | "sinhf" | "tanf" => {
// FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
let f = match link_name {
@@ -591,9 +589,18 @@ fn emulate_foreign_item(
trace!("sysconf() called with name {}", name);
// TODO: Cache the sysconf integers via Miri's global cache.
let paths = &[
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)),
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
(&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)),
(
&["libc", "_SC_PAGESIZE"],
Scalar::from_int(PAGE_SIZE, dest.layout.size),
),
(
&["libc", "_SC_GETPW_R_SIZE_MAX"],
Scalar::from_int(-1, dest.layout.size),
),
(
&["libc", "_SC_NPROCESSORS_ONLN"],
Scalar::from_int(NUM_CPUS, dest.layout.size),
),
];
let mut result = None;
for &(path, path_value) in paths {
@@ -603,7 +610,6 @@ fn emulate_foreign_item(
result = Some(path_value);
break;
}
}
}
if let Some(result) = result {
@@ -644,11 +650,14 @@ fn emulate_foreign_item(
// Create key and write it into the memory where `key_ptr` wants it.
let key = this.machine.tls.create_tls_key(dtor) as u128;
if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128)
{
throw_unsup!(OutOfTls);
}
let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)?
let key_ptr = this
.memory()
.check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)?
.expect("cannot be a ZST");
this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
tcx,
@@ -681,8 +690,10 @@ fn emulate_foreign_item(
}
// Stack size/address stuff.
"pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" |
"pthread_attr_setstacksize" => {
"pthread_attr_init"
| "pthread_attr_destroy"
| "pthread_self"
| "pthread_attr_setstacksize" => {
this.write_null(dest)?;
}
"pthread_attr_getstack" => {
@@ -708,12 +719,22 @@ fn emulate_foreign_item(
}
// Stub out calls for condvar, mutex and rwlock, to just return `0`.
"pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
"pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
"pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
"pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
"pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
"pthread_cond_destroy" => {
"pthread_mutexattr_init"
| "pthread_mutexattr_settype"
| "pthread_mutex_init"
| "pthread_mutexattr_destroy"
| "pthread_mutex_lock"
| "pthread_mutex_unlock"
| "pthread_mutex_destroy"
| "pthread_rwlock_rdlock"
| "pthread_rwlock_unlock"
| "pthread_rwlock_wrlock"
| "pthread_rwlock_destroy"
| "pthread_condattr_init"
| "pthread_condattr_setclock"
| "pthread_cond_init"
| "pthread_condattr_destroy"
| "pthread_cond_destroy" => {
this.write_null(dest)?;
}
@@ -745,13 +766,13 @@ fn emulate_foreign_item(
}
"_tlv_atexit" => {
// FIXME: register the destructor.
},
}
"_NSGetArgc" => {
this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
},
}
"_NSGetArgv" => {
this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
},
}
"SecRandomCopyBytes" => {
let len = this.read_scalar(args[1])?.to_usize(this)?;
let ptr = this.read_scalar(args[2])?.not_undef()?;
@@ -792,42 +813,45 @@ fn emulate_foreign_item(
}
"SetLastError" => {
let err = this.read_scalar(args[0])?.to_u32()?;
this.machine.last_error = err;
this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
}
"GetLastError" => {
this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?;
let last_error = this.get_last_error()?;
this.write_scalar(last_error, dest)?;
}
"AddVectoredExceptionHandler" => {
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
},
"InitializeCriticalSection" |
"EnterCriticalSection" |
"LeaveCriticalSection" |
"DeleteCriticalSection" => {
}
"InitializeCriticalSection"
| "EnterCriticalSection"
| "LeaveCriticalSection"
| "DeleteCriticalSection" => {
// Nothing to do, not even a return value.
},
"GetModuleHandleW" |
"GetProcAddress" |
"TryEnterCriticalSection" |
"GetConsoleScreenBufferInfo" |
"SetConsoleTextAttribute" => {
}
"GetModuleHandleW"
| "GetProcAddress"
| "TryEnterCriticalSection"
| "GetConsoleScreenBufferInfo"
| "SetConsoleTextAttribute" => {
// Pretend these do not exist / nothing happened, by returning zero.
this.write_null(dest)?;
},
}
"GetSystemInfo" => {
let system_info = this.deref_operand(args[0])?;
let system_info_ptr = this.check_mplace_access(system_info, None)?
let system_info_ptr = this
.check_mplace_access(system_info, None)?
.expect("cannot be a ZST");
// Initialize with `0`.
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
this.memory_mut()
.get_mut(system_info_ptr.alloc_id)?
.write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
// Set number of processors.
let dword_size = Size::from_bytes(4);
let offset = 2*dword_size + 3*tcx.pointer_size();
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
let offset = 2 * dword_size + 3 * tcx.pointer_size();
this.memory_mut()
.get_mut(system_info_ptr.alloc_id)?
.write_scalar(
tcx,
system_info_ptr.offset(offset, tcx)?,
@@ -844,7 +868,8 @@ fn emulate_foreign_item(
// Figure out how large a TLS key actually is. This is `c::DWORD`.
if dest.layout.size.bits() < 128
&& key >= (1u128 << dest.layout.size.bits() as u128) {
&& key >= (1u128 << dest.layout.size.bits() as u128)
{
throw_unsup!(OutOfTls);
}
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
@@ -879,7 +904,9 @@ fn emulate_foreign_item(
// stdout/stderr
use std::io::{self, Write};
let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
let buf_cont = this
.memory()
.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
let res = if handle == -11 {
io::stdout().write(buf_cont)
} else {
@@ -907,7 +934,7 @@ fn emulate_foreign_item(
}
"GetEnvironmentVariableW" => {
// This is not the env var you are looking for.
this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
this.write_null(dest)?;
}
"GetCommandLineW" => {
@@ -922,9 +949,7 @@ fn emulate_foreign_item(
}
// We can't execute anything else.
_ => {
throw_unsup_format!("can't call foreign function: {}", link_name)
}
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
}
this.goto_block(Some(ret))?;
@@ -934,7 +959,10 @@ fn emulate_foreign_item(
/// Evaluates the scalar at the specified path. Returns Some(val)
/// if the path could be resolved, and None otherwise
fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
fn eval_path_scalar(
&mut self,
path: &[&str],
) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
let this = self.eval_context_mut();
if let Ok(instance) = this.resolve_path(path) {
let cid = GlobalId {
@@ -948,12 +976,44 @@ fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<Scala
return Ok(None);
}
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
self
.eval_context_mut()
fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
self.eval_context_mut()
.eval_path_scalar(&["libc", name])?
.ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into())
.and_then(|scalar| scalar.to_i32())
.and_then(|scalar| scalar.not_undef())
}
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
self.eval_libc(name).and_then(|scalar| scalar.to_i32())
}
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let tcx = &{ this.tcx.tcx };
let errno_ptr = this.machine.last_error.unwrap();
this.memory_mut().get_mut(errno_ptr.alloc_id)?.write_scalar(
tcx,
errno_ptr,
scalar.into(),
Size::from_bits(32),
)
}
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
let this = self.eval_context_mut();
let tcx = &{ this.tcx.tcx };
let errno_ptr = this.machine.last_error.unwrap();
this.memory()
.get(errno_ptr.alloc_id)?
.read_scalar(tcx, errno_ptr, Size::from_bits(32))?
.not_undef()
}
fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> {
self.eval_context_mut().set_last_error(Scalar::from_int(
e.raw_os_error().unwrap(),
Size::from_bits(32),
))
}
}
+5 -3
View File
@@ -221,7 +221,8 @@ fn get_handle_and<F, T: From<i32>>(&mut self, fd: i32, f: F) -> InterpResult<'tc
if let Some(handle) = this.machine.file_handler.handles.get(&fd) {
f(handle)
} else {
this.machine.last_error = this.eval_libc_i32("EBADF")? as u32;
let ebadf = this.eval_libc("EBADF")?;
this.set_last_error(ebadf)?;
Ok((-1).into())
}
}
@@ -244,7 +245,8 @@ fn remove_handle_and<F, T: From<i32>>(&mut self, fd: i32, mut f: F) -> InterpRes
if let Some(handle) = this.machine.file_handler.handles.remove(&fd) {
f(handle, this)
} else {
this.machine.last_error = this.eval_libc_i32("EBADF")? as u32;
let ebadf = this.eval_libc("EBADF")?;
this.set_last_error(ebadf)?;
Ok((-1).into())
}
}
@@ -262,7 +264,7 @@ fn consume_result<T: From<i32>>(
match result {
Ok(ok) => Ok(ok),
Err(e) => {
self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32;
self.eval_context_mut().consume_io_error(e)?;
Ok((-1).into())
}
}