]> git.lizzy.rs Git - rust.git/blobdiff - src/shims/foreign_items.rs
Fix merge conflicts
[rust.git] / src / shims / foreign_items.rs
index 41966c5f0d9cb91c935c0862969ea1a4661810d9..1933aee1151dc3b3b4cef7b8a5a610ca1ff55b90 100644 (file)
@@ -1,6 +1,9 @@
-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;
 
@@ -37,42 +40,32 @@ 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};
         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(())
     }
@@ -89,25 +82,18 @@ 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
+                        .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),
@@ -135,23 +121,23 @@ fn emulate_foreign_item(
             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 {
             "__rust_start_panic" | "panic_impl" => {
-                return err!(MachineError("the evaluated program panicked".to_string()));
+                throw_unsup_format!("the evaluated program panicked");
             }
             "exit" | "ExitProcess" => {
                 // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway
                 let code = this.read_scalar(args[0])?.to_i32()?;
-                return err!(Exit(code));
+                return Err(InterpError::Exit(code).into());
             }
-            _ => if dest.is_none() {
-                return err!(Unimplemented(
-                    format!("can't call diverging foreign function: {}", link_name),
-                ));
+            _ => {
+                if dest.is_none() {
+                    throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
+                }
             }
         }
 
@@ -167,7 +153,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(|| InterpError::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)?;
             }
@@ -177,25 +165,22 @@ fn emulate_foreign_item(
                 let size = this.read_scalar(args[2])?.to_usize(this)?;
                 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
                 if !align.is_power_of_two() {
-                    return err!(HeapAllocNonPowerOfTwoAlignment(align));
+                    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() {
-                    return err!(MachineError(format!(
+                    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())?;
                 }
@@ -216,38 +201,38 @@ fn emulate_foreign_item(
                 let size = this.read_scalar(args[0])?.to_usize(this)?;
                 let align = this.read_scalar(args[1])?.to_usize(this)?;
                 if size == 0 {
-                    return err!(HeapAllocZeroBytes);
+                    throw_unsup!(HeapAllocZeroBytes);
                 }
                 if !align.is_power_of_two() {
-                    return err!(HeapAllocNonPowerOfTwoAlignment(align));
+                    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" => {
                 let size = this.read_scalar(args[0])?.to_usize(this)?;
                 let align = this.read_scalar(args[1])?.to_usize(this)?;
                 if size == 0 {
-                    return err!(HeapAllocZeroBytes);
+                    throw_unsup!(HeapAllocZeroBytes);
                 }
                 if !align.is_power_of_two() {
-                    return err!(HeapAllocNonPowerOfTwoAlignment(align));
+                    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" => {
@@ -255,15 +240,18 @@ fn emulate_foreign_item(
                 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
                 let align = this.read_scalar(args[2])?.to_usize(this)?;
                 if old_size == 0 {
-                    return err!(HeapAllocZeroBytes);
+                    throw_unsup!(HeapAllocZeroBytes);
                 }
                 if !align.is_power_of_two() {
-                    return err!(HeapAllocNonPowerOfTwoAlignment(align));
+                    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(),
                 )?;
             }
@@ -273,13 +261,13 @@ fn emulate_foreign_item(
                 let align = this.read_scalar(args[2])?.to_usize(this)?;
                 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
                 if old_size == 0 || new_size == 0 {
-                    return err!(HeapAllocZeroBytes);
+                    throw_unsup!(HeapAllocZeroBytes);
                 }
                 if !align.is_power_of_two() {
-                    return err!(HeapAllocNonPowerOfTwoAlignment(align));
+                    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),
@@ -290,7 +278,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)?;
 
@@ -298,32 +287,26 @@ fn emulate_foreign_item(
                 // 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 => {
-                        return err!(Unimplemented(
-                            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)?;
@@ -340,15 +323,16 @@ fn emulate_foreign_item(
                 // 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,
@@ -359,16 +343,13 @@ fn emulate_foreign_item(
                 )?;
                 let mut args = this.frame().body.args_iter();
 
-                let arg_local = args.next().ok_or_else(||
-                    InterpError::AbiViolation(
-                        "Argument to __rust_maybe_catch_panic does not take enough arguments."
-                            .to_owned(),
-                    ),
-                )?;
-                let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
+                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)?;
@@ -383,8 +364,8 @@ fn emulate_foreign_item(
                 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) {
@@ -394,18 +375,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)?;
@@ -419,7 +401,7 @@ fn emulate_foreign_item(
                 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);
@@ -431,91 +413,66 @@ fn emulate_foreign_item(
                 }
             }
 
+            "__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.
@@ -534,26 +491,35 @@ fn emulate_foreign_item(
                         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 {
@@ -590,7 +556,8 @@ fn emulate_foreign_item(
                 };
                 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()?);
@@ -602,6 +569,24 @@ fn emulate_foreign_item(
                 };
                 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" => {
@@ -614,9 +599,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 {
@@ -626,15 +620,12 @@ fn emulate_foreign_item(
                             result = Some(path_value);
                             break;
                         }
-
                     }
                 }
                 if let Some(result) = result {
                     this.write_scalar(result, dest)?;
                 } else {
-                    return err!(Unimplemented(
-                        format!("Unimplemented sysconf name: {}", name),
-                    ));
+                    throw_unsup_format!("Unimplemented sysconf name: {}", name)
                 }
             }
 
@@ -649,11 +640,11 @@ fn emulate_foreign_item(
 
             // 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,
                 };
 
@@ -661,24 +652,20 @@ fn emulate_foreign_item(
                 // This is `libc::pthread_key_t`.
                 let key_type = args[0].layout.ty
                     .builtin_deref(true)
-                    .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
+                    .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) {
-                    return err!(OutOfTls);
+                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)?;
@@ -704,8 +691,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" => {
@@ -725,18 +714,28 @@ fn emulate_foreign_item(
                 this.write_null(dest)?;
             }
 
-            // We don't support threading.
-            "pthread_create" => {
-                return err!(Unimplemented(format!("Miri does not support threading")));
+            // We don't support threading. (Also for Windows.)
+            "pthread_create" | "CreateThread" => {
+                throw_unsup_format!("Miri does not support threading");
             }
 
             // 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)?;
             }
 
@@ -768,17 +767,17 @@ 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()?;
-                this.gen_random(len as usize, ptr)?;
+                this.gen_random(ptr, len as usize)?;
                 this.write_null(dest)?;
             }
 
@@ -815,48 +814,46 @@ 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, align) = system_info.to_scalar_ptr_align();
-                let system_info_ptr = this.memory()
-                    .check_ptr_access(
-                        system_info_ptr,
-                        system_info.layout.size,
-                        align,
-                    )?
+                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)?,
@@ -873,8 +870,9 @@ 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) {
-                    return err!(OutOfTls);
+                    && key >= (1u128 << dest.layout.size.bits() as u128)
+                {
+                    throw_unsup!(OutOfTls);
                 }
                 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
             }
@@ -908,7 +906,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 {
@@ -936,7 +936,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" => {
@@ -946,16 +946,12 @@ fn emulate_foreign_item(
             "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.
-            _ => {
-                return err!(Unimplemented(
-                    format!("can't call foreign function: {}", link_name),
-                ));
-            }
+            _ => throw_unsup_format!("can't call foreign function: {}", link_name),
         }
 
         this.goto_block(Some(ret))?;
@@ -965,7 +961,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 {
@@ -978,4 +977,22 @@ fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<Scala
         }
         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(())
+}