Skip to content

Commit

Permalink
make set_last_error directly callable on a bunch of ways to represent…
Browse files Browse the repository at this point in the history
… errors
  • Loading branch information
RalfJung committed Oct 1, 2024
1 parent 88c7452 commit 9c21fd4
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 80 deletions.
2 changes: 1 addition & 1 deletion src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ pub use crate::range_map::RangeMap;
pub use crate::shims::EmulateItemResult;
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
pub use crate::shims::io_error::EvalContextExt as _;
pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
pub use crate::shims::time::EvalContextExt as _;
Expand Down
48 changes: 38 additions & 10 deletions src/tools/miri/src/shims/io_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@ use std::io;

use crate::*;

/// A representation of an IO error: either a libc error name,
/// or a host error.
#[derive(Debug)]
pub enum IoError {
LibcError(&'static str),
HostError(io::Error),
Raw(Scalar),
}
pub use self::IoError::*;

impl From<io::Error> for IoError {
fn from(value: io::Error) -> Self {
IoError::HostError(value)
}
}

impl From<io::ErrorKind> for IoError {
fn from(value: io::ErrorKind) -> Self {
IoError::HostError(value.into())
}
}

impl From<Scalar> for IoError {
fn from(value: Scalar) -> Self {
IoError::Raw(value)
}
}

// This mapping should match `decode_error_kind` in
// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
Expand Down Expand Up @@ -80,10 +108,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}

/// Sets the last error variable.
fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> {
fn set_last_error(&mut self, err: impl Into<IoError>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let errno = match err.into() {
HostError(err) => this.io_error_to_errnum(err)?,
LibcError(name) => this.eval_libc(name),
Raw(val) => val,
};
let errno_place = this.last_error_place()?;
this.write_scalar(scalar, &errno_place)
this.write_scalar(errno, &errno_place)
}

/// Gets the last error variable.
Expand Down Expand Up @@ -152,19 +185,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}

/// Sets the last OS error using a `std::io::ErrorKind`.
fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> {
self.set_last_error(self.io_error_to_errnum(err)?)
}

/// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place.
fn set_last_error_and_return(
&mut self,
err: impl Into<io::Error>,
err: impl Into<IoError>,
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
this.set_last_error(this.io_error_to_errnum(err.into())?)?;
this.set_last_error(err)?;
this.write_int(-1, dest)?;
Ok(())
}
Expand All @@ -182,7 +210,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match result {
Ok(ok) => Ok(ok),
Err(e) => {
self.eval_context_mut().set_last_error_from_io_error(e)?;
self.eval_context_mut().set_last_error(e)?;
Ok((-1).into())
}
}
Expand Down
15 changes: 6 additions & 9 deletions src/tools/miri/src/shims/unix/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Scalar::from_i32(0)) // return zero on success
} else {
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
Ok(Scalar::from_i32(-1))
}
}
Expand All @@ -203,8 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Scalar::from_i32(0))
} else {
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
Ok(Scalar::from_i32(-1))
}
}
Expand All @@ -218,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`getcwd`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
this.set_last_error(ErrorKind::PermissionDenied)?;
return Ok(Pointer::null());
}

Expand All @@ -228,10 +226,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
return Ok(buf);
}
let erange = this.eval_libc("ERANGE");
this.set_last_error(erange)?;
this.set_last_error(LibcError("ERANGE"))?;
}
Err(e) => this.set_last_error_from_io_error(e)?,
Err(e) => this.set_last_error(e)?,
}

Ok(Pointer::null())
Expand All @@ -245,7 +242,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`chdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
this.set_last_error(ErrorKind::PermissionDenied)?;

return Ok(Scalar::from_i32(-1));
}
Expand Down
8 changes: 3 additions & 5 deletions src/tools/miri/src/shims/unix/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fcntl`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
this.set_last_error(ErrorKind::PermissionDenied)?;
return Ok(Scalar::from_i32(-1));
}

Expand Down Expand Up @@ -606,8 +606,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
None => fd.read(&fd, communicate, buf, count, dest, this)?,
Some(offset) => {
let Ok(offset) = u64::try_from(offset) else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
this.write_int(-1, dest)?;
return Ok(());
};
Expand Down Expand Up @@ -651,8 +650,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
None => fd.write(&fd, communicate, buf, count, dest, this)?,
Some(offset) => {
let Ok(offset) = u64::try_from(offset) else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
this.write_int(-1, dest)?;
return Ok(());
};
Expand Down
22 changes: 10 additions & 12 deletions src/tools/miri/src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
None => {
let einval = this.eval_libc("ENOMEM");
this.set_last_error(einval)?;
let enmem = this.eval_libc("ENOMEM");
this.set_last_error(enmem)?;
this.write_null(dest)?;
}
Some(len) => {
Expand Down Expand Up @@ -646,13 +646,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let chunk_size = CpuAffinityMask::chunk_size(this);

if this.ptr_is_null(mask)? {
let einval = this.eval_libc("EFAULT");
this.set_last_error(einval)?;
let efault = this.eval_libc("EFAULT");
this.set_last_error(efault)?;
this.write_int(-1, dest)?;
} else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
// we only copy whole chunks of size_of::<c_ulong>()
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
this.write_int(-1, dest)?;
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
let cpuset = cpuset.clone();
Expand All @@ -662,8 +661,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_null(dest)?;
} else {
// The thread whose ID is pid could not be found
let einval = this.eval_libc("ESRCH");
this.set_last_error(einval)?;
let esrch = this.eval_libc("ESRCH");
this.set_last_error(esrch)?;
this.write_int(-1, dest)?;
}
}
Expand All @@ -689,8 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
};

if this.ptr_is_null(mask)? {
let einval = this.eval_libc("EFAULT");
this.set_last_error(einval)?;
let efault = this.eval_libc("EFAULT");
this.set_last_error(efault)?;
this.write_int(-1, dest)?;
} else {
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
Expand All @@ -707,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
None => {
// The intersection between the mask and the available CPUs was empty.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.set_last_error(LibcError("EINVAL"))?;
this.write_int(-1, dest)?;
}
}
Expand Down
Loading

0 comments on commit 9c21fd4

Please sign in to comment.