Fix merge conflicts

This commit is contained in:
Christian Poveda 2019-10-21 08:49:49 -05:00
commit 72bd25de83
13 changed files with 116 additions and 112 deletions

2
miri
View file

@ -54,7 +54,7 @@ build_sysroot() {
# Build once, for the user to see.
cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@"
# Call again, to just set env var.
eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@")
export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --print-sysroot "$@")"
}
# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account

View file

@ -1 +1 @@
fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f
7979016aff545f7b41cc517031026020b340989d

View file

@ -259,6 +259,10 @@ fn setup(ask_user: bool) {
// First, we need xargo.
if xargo_version().map_or(true, |v| v < (0, 3, 16)) {
if std::env::var("XARGO").is_ok() {
// The user manually gave us a xargo binary; don't do anything automatically.
show_error(format!("Your xargo is too old; please upgrade to the latest version"))
}
let mut cmd = cargo();
cmd.args(&["install", "xargo", "-f"]);
ask_to_run(cmd, ask_user, "install a recent enough xargo");
@ -310,7 +314,7 @@ path = "lib.rs"
File::create(dir.join("lib.rs")).unwrap();
// Prepare xargo invocation.
let target = get_arg_flag_value("--target");
let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable
let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
let mut command = xargo();
command.arg("build").arg("-q");
command.current_dir(&dir);
@ -339,13 +343,9 @@ path = "lib.rs"
};
let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags
if print_env {
// Escape an arbitrary string for the shell: by wrapping it in `'`, the only special
// character we have to worry about is `'` itself. Everything else is taken literally
// in these strings. `'` is encoded as `'"'"'`: the outer `'` end and being a
// `'`-quoted string, respectively; the `"'"` in the middle represents a single `'`.
// (We could use `'\''` instead of `'"'"'` if we wanted but let's avoid backslashes.)
println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#));
if print_sysroot {
// Print just the sysroot and nothing else; this way we do not need any escaping.
println!("{}", sysroot.display());
} else if !ask_user {
println!("A libstd for Miri is now available in `{}`.", sysroot.display());
}

View file

@ -162,7 +162,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
MiriMemoryKind::Env.into(),
);
ecx.machine.cmd_line = Some(cmd_ptr);
// Store the UTF-16 string.
// Store the UTF-16 string. We just allocated so we know the bounds are fine.
let char_size = Size::from_bytes(2);
let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?;
let mut cur_ptr = cmd_ptr;
@ -177,17 +177,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
}
}
assert!(
args.next().is_none(),
"start lang item has more arguments than expected"
);
args.next().expect_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;
ecx.machine.last_error = Some(errno_place);
Ok(ecx)
}

View file

@ -95,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
let this = self.eval_context_mut();
// Don't forget the bounds check.
let ptr = this.memory.check_ptr_access(
ptr,
Size::from_bytes(len as u64),
@ -346,6 +347,70 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok(())
}
/// Sets the last error variable.
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let errno_place = this.machine.last_error.unwrap();
this.write_scalar(scalar, errno_place.into())
}
/// Gets the last error variable.
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
let this = self.eval_context_mut();
let errno_place = this.machine.last_error.unwrap();
this.read_scalar(errno_place.into())?.not_undef()
}
/// Sets the last OS error using a `std::io::Error`. This function tries to produce the most
/// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error.
fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> {
use std::io::ErrorKind::*;
let this = self.eval_context_mut();
let target = &this.tcx.tcx.sess.target.target;
let last_error = if target.options.target_family == Some("unix".to_owned()) {
this.eval_libc(match e.kind() {
ConnectionRefused => "ECONNREFUSED",
ConnectionReset => "ECONNRESET",
PermissionDenied => "EPERM",
BrokenPipe => "EPIPE",
NotConnected => "ENOTCONN",
ConnectionAborted => "ECONNABORTED",
AddrNotAvailable => "EADDRNOTAVAIL",
AddrInUse => "EADDRINUSE",
NotFound => "ENOENT",
Interrupted => "EINTR",
InvalidInput => "EINVAL",
TimedOut => "ETIMEDOUT",
AlreadyExists => "EEXIST",
WouldBlock => "EWOULDBLOCK",
_ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e)
})?
} else {
// FIXME: we have to implement the windows' equivalent of this.
throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os)
};
this.set_last_error(last_error)
}
/// Helper function that consumes an `std::io::Result<T>` and returns an
/// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
/// `Ok(-1)` and sets the last OS error accordingly.
///
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
/// functions return different integer types (like `read`, that returns an `i64`)
fn try_unwrap_io_result<T: From<i32>>(
&mut self,
result: std::io::Result<T>,
) -> InterpResult<'tcx, T> {
match result {
Ok(ok) => Ok(ok),
Err(e) => {
self.eval_context_mut().set_last_error_from_io_error(e)?;
Ok((-1).into())
}
}
}
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
/// the Unix APIs usually handle.
fn read_os_string_from_c_string(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString> {

View file

@ -1,4 +1,5 @@
#![feature(rustc_private)]
#![feature(option_expect_none, option_unwrap_none)]
#![warn(rust_2018_idioms)]
#![allow(clippy::cast_lossless)]

View file

@ -91,8 +91,8 @@ pub struct Evaluator<'tcx> {
pub(crate) argv: Option<Pointer<Tag>>,
pub(crate) cmd_line: Option<Pointer<Tag>>,
/// Last OS error.
pub(crate) last_error: Option<Pointer<Tag>>,
/// Last OS error location in memory. It is a 32-bit integer.
pub(crate) last_error: Option<MPlaceTy<'tcx, Tag>>,
/// TLS state.
pub(crate) tls: TlsData<'tcx>,
@ -244,10 +244,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?;
// No more arguments.
assert!(
args.next().is_none(),
"`exchange_malloc` lang item has more arguments than expected"
);
args.next().expect_none("`exchange_malloc` lang item has more arguments than expected");
Ok(())
}

View file

@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let erange = this.eval_libc("ERANGE")?;
this.set_last_error(erange)?;
}
Err(e) => this.consume_io_error(e)?,
Err(e) => this.set_last_error_from_io_error(e)?,
}
Ok(Scalar::ptr_null(&*this.tcx))
}
@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
match env::set_current_dir(path) {
Ok(()) => Ok(0),
Err(e) => {
this.consume_io_error(e)?;
this.set_last_error_from_io_error(e)?;
Ok(-1)
}
}

View file

@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
.memory
.allocate(Size::from_bytes(size), align, kind.into());
if zero_init {
// We just allocated this, the access cannot fail
// We just allocated this, the access is definitely in-bounds.
this.memory
.get_mut(ptr.alloc_id)
.unwrap()
@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Align::from_bytes(align).unwrap(),
MiriMemoryKind::Rust.into(),
);
// We just allocated this, the access cannot fail
// We just allocated this, the access is definitely in-bounds.
this.memory
.get_mut(ptr.alloc_id)
.unwrap()
@ -349,10 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
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)?;
@ -417,8 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
"__errno_location" | "__error" => {
let errno_scalar: Scalar<Tag> = this.machine.last_error.unwrap().into();
this.write_scalar(errno_scalar, dest)?;
let errno_place = this.machine.last_error.unwrap();
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
}
"getenv" => {
@ -643,7 +640,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// 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()?)? {
@ -668,16 +665,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
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.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)?;
@ -856,6 +844,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
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
.get_mut(system_info_ptr.alloc_id)?
@ -988,33 +977,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
return Ok(None);
}
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let errno_ptr = this.machine.last_error.unwrap();
this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar(
&*this.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 errno_ptr = this.machine.last_error.unwrap();
this.memory
.get(errno_ptr.alloc_id)?
.read_scalar(&*this.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),
))
}
}
// Shims the linux 'getrandom()' syscall.

View file

@ -7,6 +7,7 @@ use rustc::ty::layout::Size;
use crate::stacked_borrows::Tag;
use crate::*;
#[derive(Debug)]
pub struct FileHandle {
file: File,
}
@ -20,7 +21,7 @@ impl Default for FileHandler {
fn default() -> Self {
FileHandler {
handles: Default::default(),
// 0, 1 and 2 are reserved for stdin, stdout and stderr
// 0, 1 and 2 are reserved for stdin, stdout and stderr.
low: 3,
}
}
@ -99,11 +100,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let fd = options.open(path).map(|file| {
let mut fh = &mut this.machine.file_handler;
fh.low += 1;
fh.handles.insert(fh.low, FileHandle { file });
fh.handles.insert(fh.low, FileHandle { file }).unwrap_none();
fh.low
});
this.consume_result(fd)
this.try_unwrap_io_result(fd)
}
fn fcntl(
@ -118,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let fd = this.read_scalar(fd_op)?.to_i32()?;
let cmd = this.read_scalar(cmd_op)?.to_i32()?;
// We only support getting the flags for a descriptor
// We only support getting the flags for a descriptor.
if cmd == this.eval_libc_i32("F_GETFD")? {
// Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
@ -139,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let fd = this.read_scalar(fd_op)?.to_i32()?;
this.remove_handle_and(fd, |handle, this| {
this.consume_result(handle.file.sync_all().map(|_| 0i32))
this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32))
})
}
@ -154,25 +155,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_no_isolation("read")?;
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
// Reading zero bytes should not change `buf`
// Reading zero bytes should not change `buf`.
if count == 0 {
return Ok(0);
}
let fd = this.read_scalar(fd_op)?.to_i32()?;
let buf_scalar = this.read_scalar(buf_op)?.not_undef()?;
// Remove the file handle to avoid borrowing issues
// Remove the file handle to avoid borrowing issues.
this.remove_handle_and(fd, |mut handle, this| {
// Don't use `?` to avoid returning before reinserting the handle
// Don't use `?` to avoid returning before reinserting the handle.
let bytes = this.force_ptr(buf_scalar).and_then(|buf| {
this.memory
.get_mut(buf.alloc_id)?
.get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count))
.map(|buffer| handle.file.read(buffer))
});
// Reinsert the file handle
this.machine.file_handler.handles.insert(fd, handle);
this.consume_result(bytes?.map(|bytes| bytes as i64))
this.machine.file_handler.handles.insert(fd, handle).unwrap_none();
this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64))
})
}
@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_no_isolation("write")?;
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
// Writing zero bytes should not change `buf`
// Writing zero bytes should not change `buf`.
if count == 0 {
return Ok(0);
}
@ -200,8 +200,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
.get_bytes(&*this.tcx, buf, Size::from_bytes(count))
.map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64))
});
this.machine.file_handler.handles.insert(fd, handle);
this.consume_result(bytes?)
this.machine.file_handler.handles.insert(fd, handle).unwrap_none();
this.try_unwrap_io_result(bytes?)
})
}
@ -214,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let result = remove_file(path).map(|_| 0);
this.consume_result(result)
this.try_unwrap_io_result(result)
}
/// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it
@ -224,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor).
///
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
/// functions return different integer types (like `read`, that returns an `i64`)
/// functions return different integer types (like `read`, that returns an `i64`).
fn get_handle_and<F, T: From<i32>>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T>
where
F: Fn(&FileHandle) -> InterpResult<'tcx, T>,
@ -248,7 +248,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor).
///
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
/// functions return different integer types (like `read`, that returns an `i64`)
/// functions return different integer types (like `read`, that returns an `i64`).
fn remove_handle_and<F, T: From<i32>>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T>
where
F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>,
@ -262,23 +262,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok((-1).into())
}
}
/// Helper function that consumes an `std::io::Result<T>` and returns an
/// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an
/// OS error using `std::io::Error::raw_os_error`.
///
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
/// functions return different integer types (like `read`, that returns an `i64`)
fn consume_result<T: From<i32>>(
&mut self,
result: std::io::Result<T>,
) -> InterpResult<'tcx, T> {
match result {
Ok(ok) => Ok(ok),
Err(e) => {
self.eval_context_mut().consume_io_error(e)?;
Ok((-1).into())
}
}
}
}

View file

@ -356,9 +356,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
_ => {
// Do it in memory
let mplace = this.force_allocation(dest)?;
assert!(mplace.meta.is_none());
mplace.meta.unwrap_none();
// not a zst, must be valid pointer
let ptr = mplace.ptr.to_ptr()?;
// we know the return place is in-bounds
this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?;
}
}
@ -546,8 +547,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
_ => {
// Do it in memory
let mplace = this.force_allocation(dest)?;
assert!(mplace.meta.is_none());
mplace.meta.unwrap_none();
let ptr = mplace.ptr.to_ptr()?;
// We know the return place is in-bounds
this.memory
.get_mut(ptr.alloc_id)?
.mark_definedness(ptr, dest.layout.size, false);

View file

@ -53,7 +53,7 @@ impl<'tcx> TlsData<'tcx> {
data: None,
dtor,
},
);
).unwrap_none();
trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
new_key
}

View file

@ -172,7 +172,7 @@ impl GlobalState {
pub fn new_call(&mut self) -> CallId {
let id = self.next_call_id;
trace!("new_call: Assigning ID {}", id);
self.active_calls.insert(id);
assert!(self.active_calls.insert(id));
self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap();
id
}
@ -189,7 +189,7 @@ impl GlobalState {
self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| {
let tag = Tag::Tagged(self.new_ptr());
trace!("New allocation {:?} has base tag {:?}", id, tag);
self.base_ptr_ids.insert(id, tag);
self.base_ptr_ids.insert(id, tag).unwrap_none();
tag
})
}