-use rustc::ty::layout::{Align, LayoutOf, Size};
+use std::convert::TryInto;
+
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;
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};
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
+ .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();
+ // We just allocated this, the access is definitely in-bounds.
+ this.memory
+ .get_mut(ptr.alloc_id)
+ .unwrap()
+ .write_repeat(&*this.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.deallocate(ptr, None, kind.into())?;
}
Ok(())
}
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
+ .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(),
- )?;
+ this.memory.deallocate(old_ptr, None, kind.into())?;
Ok(Scalar::from_int(0, this.pointer_size()))
} else {
- let new_ptr = memory.reallocate(
+ let new_ptr = this.memory.reallocate(
old_ptr,
None,
Size::from_bytes(new_size),
None => this.tcx.item_name(def_id).as_str(),
};
// Strip linker suffixes (seen on 32-bit macOS).
- let link_name = link_name.get().trim_end_matches("$UNIX2003");
- let tcx = &{this.tcx.tcx};
+ let link_name = link_name.trim_end_matches("$UNIX2003");
+ let tcx = &{ this.tcx.tcx };
// First: functions that diverge.
match link_name {
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);
+ }
}
}
"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)?;
}
if !align.is_power_of_two() {
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
}
- /*
- FIXME: This check is disabled because rustc violates it.
- See <https://github.com/rust-lang/rust/issues/62251>.
if align < this.pointer_size().bytes() {
throw_ub_format!(
"posix_memalign: alignment must be at least the size of a pointer, but is {}",
align,
);
}
- */
+
if size == 0 {
this.write_null(ret.into())?;
} else {
- let ptr = this.memory_mut().allocate(
+ let ptr = this.memory.allocate(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
- MiriMemoryKind::C.into()
+ MiriMemoryKind::C.into(),
);
this.write_scalar(Scalar::Ptr(ptr), ret.into())?;
}
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.allocate(
+ Size::from_bytes(size),
+ Align::from_bytes(align).unwrap(),
+ MiriMemoryKind::Rust.into(),
+ );
this.write_scalar(Scalar::Ptr(ptr), dest)?;
}
"__rust_alloc_zeroed" => {
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()
- );
- // 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();
+ let ptr = this.memory.allocate(
+ Size::from_bytes(size),
+ Align::from_bytes(align).unwrap(),
+ MiriMemoryKind::Rust.into(),
+ );
+ // We just allocated this, the access is definitely in-bounds.
+ this.memory
+ .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" => {
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = this.force_ptr(ptr)?;
- this.memory_mut().deallocate(
+ this.memory.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(),
)?;
}
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
}
let align = Align::from_bytes(align).unwrap();
- let new_ptr = this.memory_mut().reallocate(
+ let new_ptr = this.memory.reallocate(
ptr,
Some((Size::from_bytes(old_size), align)),
Size::from_bytes(new_size),
}
"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)?;
// is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
match this.read_scalar(args[0])?.to_usize(this)? {
id if id == sys_getrandom => {
- let ptr = this.read_scalar(args[1])?.not_undef()?;
- let len = this.read_scalar(args[2])?.to_usize(this)?;
-
- // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
- // neither of which have any effect on our current PRNG
- let _flags = this.read_scalar(args[3])?.to_i32()?;
-
- this.gen_random(len as usize, ptr)?;
- this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
- }
- id => {
- throw_unsup_format!("miri does not support syscall ID {}", id)
+ // The first argument is the syscall id,
+ // so skip over it.
+ linux_getrandom(this, &args[1..], dest)?;
}
+ id => throw_unsup_format!("miri does not support syscall ID {}", id),
}
}
+ "getrandom" => {
+ linux_getrandom(this, args, dest)?;
+ }
+
"dlsym" => {
let _handle = this.read_scalar(args[0])?;
let symbol = this.read_scalar(args[1])?.not_undef()?;
- let symbol_name = this.memory().read_c_str(symbol)?;
+ let symbol_name = this.memory.read_c_str(symbol)?;
let err = format!("bad c unicode symbol: {:?}", symbol_name);
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
if let Some(dlsym) = Dlsym::from_str(symbol_name)? {
- let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym));
+ let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
this.write_scalar(Scalar::from(ptr), dest)?;
} else {
this.write_null(dest)?;
// We abort on panic, so not much is going on here, but we still have to call the closure.
let f = this.read_scalar(args[0])?.not_undef()?;
let data = this.read_scalar(args[1])?.not_undef()?;
- let f_instance = this.memory().get_fn(f)?.as_instance()?;
+ let f_instance = this.memory.get_fn(f)?.as_instance()?;
this.write_null(dest)?;
trace!("__rust_maybe_catch_panic: {:?}", f_instance);
// Now we make a function call.
// 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)?;
- let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
+ let mir = this.load_mir(f_instance.def, None)?;
+ let ret_place =
+ MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into();
this.push_stack_frame(
f_instance,
mir.span,
)?;
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");
+ args.next().expect_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)?;
let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
let result = {
- let left_bytes = this.memory().read_bytes(left, n)?;
- let right_bytes = this.memory().read_bytes(right, n)?;
+ let left_bytes = this.memory.read_bytes(left, n)?;
+ let right_bytes = this.memory.read_bytes(right, n)?;
use std::cmp::Ordering::*;
match left_bytes.cmp(right_bytes) {
}
};
- 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)?;
let val = this.read_scalar(args[1])?.to_i32()? as u8;
let num = this.read_scalar(args[2])?.to_usize(this)?;
let idx = this
- .memory()
+ .memory
.read_bytes(ptr, Size::from_bytes(num))?
.iter()
.position(|&c| c == val);
}
}
+ "__errno_location" | "__error" => {
+ let errno_place = this.machine.last_error.unwrap();
+ this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
+ }
+
"getenv" => {
- let result = {
- let name_ptr = this.read_scalar(args[0])?.not_undef()?;
- let name = this.memory().read_c_str(name_ptr)?;
- match this.machine.env_vars.get(name) {
- Some(&var) => Scalar::Ptr(var),
- None => Scalar::ptr_null(&*this.tcx),
- }
- };
+ let result = this.getenv(args[0])?;
this.write_scalar(result, dest)?;
}
"unsetenv" => {
- let mut success = None;
- {
- let name_ptr = this.read_scalar(args[0])?.not_undef()?;
- if !this.is_null(name_ptr)? {
- let name = this.memory().read_c_str(name_ptr)?.to_owned();
- if !name.is_empty() && !name.contains(&b'=') {
- success = Some(this.machine.env_vars.remove(&name));
- }
- }
- }
- if let Some(old) = success {
- if let Some(var) = old {
- this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
- }
- this.write_null(dest)?;
- } else {
- this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
- }
+ let result = this.unsetenv(args[0])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}
"setenv" => {
- let mut new = None;
- {
- let name_ptr = this.read_scalar(args[0])?.not_undef()?;
- let value_ptr = this.read_scalar(args[1])?.not_undef()?;
- let value = this.memory().read_c_str(value_ptr)?;
- if !this.is_null(name_ptr)? {
- let name = this.memory().read_c_str(name_ptr)?;
- if !name.is_empty() && !name.contains(&b'=') {
- new = Some((name.to_owned(), value.to_owned()));
- }
- }
- }
- if let Some((name, value)) = new {
- // `+1` for the null terminator.
- let value_copy = this.memory_mut().allocate(
- Size::from_bytes((value.len() + 1) as u64),
- Align::from_bytes(1).unwrap(),
- MiriMemoryKind::Env.into(),
- );
- // We just allocated these, so the write cannot fail.
- let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap();
- alloc.write_bytes(tcx, value_copy, &value).unwrap();
- let trailing_zero_ptr = value_copy.offset(
- Size::from_bytes(value.len() as u64),
- tcx,
- ).unwrap();
- alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap();
-
- if let Some(var) = this.machine.env_vars.insert(
- name.to_owned(),
- value_copy,
- )
- {
- this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
- }
- this.write_null(dest)?;
- } else {
- this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
- }
+ let result = this.setenv(args[0], args[1])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "getcwd" => {
+ let result = this.getcwd(args[0], args[1])?;
+ this.write_scalar(result, dest)?;
+ }
+
+ "chdir" => {
+ let result = this.chdir(args[0])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "open" | "open64" => {
+ let result = this.open(args[0], args[1])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "fcntl" => {
+ let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "close" | "close$NOCANCEL" => {
+ let result = this.close(args[0])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "read" => {
+ let result = this.read(args[0], args[1], args[2])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}
"write" => {
let fd = this.read_scalar(args[0])?.to_i32()?;
let buf = this.read_scalar(args[1])?.not_undef()?;
- let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
+ let n = this.read_scalar(args[2])?.to_usize(tcx)?;
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
let result = if fd == 1 || fd == 2 {
// stdout/stderr
use std::io::{self, Write};
- let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
+ let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?;
// We need to flush to make sure this actually appears on the screen
let res = if fd == 1 {
// Stdout is buffered, flush to make sure it appears on the screen.
Err(_) => -1,
}
} else {
- eprintln!("Miri: Ignored output to FD {}", fd);
- // Pretend it all went well.
- n as i64
+ 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)?;
+ }
+
+ "unlink" => {
+ let result = this.unlink(args[0])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "clock_gettime" => {
+ let result = this.clock_gettime(args[0], args[1])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+ }
+
+ "gettimeofday" => {
+ let result = this.gettimeofday(args[0], args[1])?;
+ this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}
"strlen" => {
let ptr = this.read_scalar(args[0])?.not_undef()?;
- let n = this.memory().read_c_str(ptr)?.len();
+ let n = this.memory.read_c_str(ptr)?.len();
this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
}
// 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 {
};
this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
}
- // underscore case for windows
+ // 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)
"_hypot" | "hypot" | "atan2" => {
// FIXME: Using host floats.
let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
};
this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?;
}
+ // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
+ "_ldexp" | "ldexp" | "scalbn" => {
+ let x = this.read_scalar(args[0])?.to_f64()?;
+ let exp = this.read_scalar(args[1])?.to_i32()?;
+
+ // Saturating cast to i16. Even those are outside the valid exponent range to
+ // `scalbn` below will do its over/underflow handling.
+ let exp = if exp > i16::max_value() as i32 {
+ i16::max_value()
+ } else if exp < i16::min_value() as i32 {
+ i16::min_value()
+ } else {
+ exp.try_into().unwrap()
+ };
+
+ let res = x.scalbn(exp);
+ this.write_scalar(Scalar::from_f64(res), dest)?;
+ }
// Some things needed for `sys::thread` initialization to go through.
"signal" | "sigaction" | "sigaltstack" => {
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 {
result = Some(path_value);
break;
}
-
}
}
if let Some(result) = result {
// Hook pthread calls that go to the thread-local storage memory subsystem.
"pthread_key_create" => {
- let key_ptr = this.read_scalar(args[0])?.not_undef()?;
+ let key_place = this.deref_operand(args[0])?;
// Extract the function type out of the signature (that seems easier than constructing it ourselves).
let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? {
- Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?),
+ Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?),
None => None,
};
// This is `libc::pthread_key_t`.
let key_type = args[0].layout.ty
.builtin_deref(true)
- .ok_or_else(|| err_ub!(Ub(format!(
+ .ok_or_else(|| err_ub_format!(
"wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
- ))))?
+ ))?
.ty;
let key_layout = this.layout_of(key_type)?;
// 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)?
- .expect("cannot be a ZST");
- this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
- tcx,
- key_ptr,
- Scalar::from_uint(key, key_layout.size).into(),
- key_layout.size,
- )?;
+ this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?;
// Return success (`0`).
this.write_null(dest)?;
}
// 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" => {
}
// 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)?;
}
}
"_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()?;
- this.gen_random(len as usize, ptr)?;
+ this.gen_random(ptr, len as usize)?;
this.write_null(dest)?;
}
}
"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");
+ // We rely on `deref_operand` doing bounds checks for us.
// Initialize with `0`.
- this.memory_mut().get_mut(system_info_ptr.alloc_id)?
+ this.memory
+ .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
+ .get_mut(system_info_ptr.alloc_id)?
.write_scalar(
tcx,
system_info_ptr.offset(offset, tcx)?,
// 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)?;
// 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 {
}
"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" => {
"SystemFunction036" => {
let ptr = this.read_scalar(args[0])?.not_undef()?;
let len = this.read_scalar(args[1])?.to_u32()?;
- this.gen_random(len as usize, ptr)?;
+ this.gen_random(ptr, len as usize)?;
this.write_scalar(Scalar::from_bool(true), dest)?;
}
// 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))?;
/// 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 {
}
return Ok(None);
}
-}
\ No newline at end of file
+}
+
+// Shims the linux 'getrandom()' syscall.
+fn linux_getrandom<'tcx>(
+ this: &mut MiriEvalContext<'_, 'tcx>,
+ args: &[OpTy<'tcx, Tag>],
+ dest: PlaceTy<'tcx, Tag>,
+) -> InterpResult<'tcx> {
+ let ptr = this.read_scalar(args[0])?.not_undef()?;
+ let len = this.read_scalar(args[1])?.to_usize(this)?;
+
+ // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
+ // neither of which have any effect on our current PRNG.
+ let _flags = this.read_scalar(args[2])?.to_i32()?;
+
+ this.gen_random(ptr, len as usize)?;
+ this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
+ Ok(())
+}