Auto merge of #3589 - RalfJung:io-error, r=RalfJung

io::Error handling: keep around the full io::Error for longer so we can give better errors

This should help with the error message in https://github.com/rust-lang/miri/issues/3587.
This commit is contained in:
bors 2024-05-08 16:23:17 +00:00
commit 15305a764d
6 changed files with 31 additions and 34 deletions

View File

@ -751,26 +751,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
/// as a platform-specific errnum. /// as a platform-specific errnum.
fn io_error_to_errnum( fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar<Provenance>> {
&self,
err_kind: std::io::ErrorKind,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref(); let this = self.eval_context_ref();
let target = &this.tcx.sess.target; let target = &this.tcx.sess.target;
if target.families.iter().any(|f| f == "unix") { if target.families.iter().any(|f| f == "unix") {
for &(name, kind) in UNIX_IO_ERROR_TABLE { for &(name, kind) in UNIX_IO_ERROR_TABLE {
if err_kind == kind { if err.kind() == kind {
return Ok(this.eval_libc(name)); return Ok(this.eval_libc(name));
} }
} }
throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind) throw_unsup_format!("unsupported io error: {err}")
} else if target.families.iter().any(|f| f == "windows") { } else if target.families.iter().any(|f| f == "windows") {
for &(name, kind) in WINDOWS_IO_ERROR_TABLE { for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
if err_kind == kind { if err.kind() == kind {
return Ok(this.eval_windows("c", name)); return Ok(this.eval_windows("c", name));
} }
} }
throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind); throw_unsup_format!("unsupported io error: {err}");
} else { } else {
throw_unsup_format!( throw_unsup_format!(
"converting io::Error into errnum is unsupported for OS {}", "converting io::Error into errnum is unsupported for OS {}",
@ -812,8 +809,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
/// Sets the last OS error using a `std::io::ErrorKind`. /// Sets the last OS error using a `std::io::ErrorKind`.
fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { 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_kind)?) self.set_last_error(self.io_error_to_errnum(err)?)
} }
/// Helper function that consumes an `std::io::Result<T>` and returns an /// Helper function that consumes an `std::io::Result<T>` and returns an
@ -829,7 +826,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match result { match result {
Ok(ok) => Ok(ok), Ok(ok) => Ok(ok),
Err(e) => { Err(e) => {
self.eval_context_mut().set_last_error_from_io_error(e.kind())?; self.eval_context_mut().set_last_error_from_io_error(e)?;
Ok((-1).into()) Ok((-1).into())
} }
} }

View File

@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`getcwd`", reject_with)?; this.reject_in_isolation("`getcwd`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(Pointer::null()); return Ok(Pointer::null());
} }
@ -241,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let erange = this.eval_libc("ERANGE"); let erange = this.eval_libc("ERANGE");
this.set_last_error(erange)?; this.set_last_error(erange)?;
} }
Err(e) => this.set_last_error_from_io_error(e.kind())?, Err(e) => this.set_last_error_from_io_error(e)?,
} }
Ok(Pointer::null()) Ok(Pointer::null())
@ -255,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`chdir`", reject_with)?; this.reject_in_isolation("`chdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match env::set_current_dir(path) { match env::set_current_dir(path) {
Ok(()) => Ok(0), Ok(()) => Ok(0),
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(-1) Ok(-1)
} }
} }

View File

@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fcntl`", reject_with)?; this.reject_in_isolation("`fcntl`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -394,7 +394,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(read_bytes) Ok(read_bytes)
} }
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(-1) Ok(-1)
} }
} }

View File

@ -378,7 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`open`", reject_with)?; this.reject_in_isolation("`open`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -434,7 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`unlink`", reject_with)?; this.reject_in_isolation("`unlink`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`symlink`", reject_with)?; this.reject_in_isolation("`symlink`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -766,7 +766,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rename`", reject_with)?; this.reject_in_isolation("`rename`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -794,7 +794,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`mkdir`", reject_with)?; this.reject_in_isolation("`mkdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -822,7 +822,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reject if isolation is enabled. // Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rmdir`", reject_with)?; this.reject_in_isolation("`rmdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1); return Ok(-1);
} }
@ -859,7 +859,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(Scalar::from_target_usize(id, this)) Ok(Scalar::from_target_usize(id, this))
} }
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(Scalar::null_ptr(this)) Ok(Scalar::null_ptr(this))
} }
} }
@ -947,7 +947,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
None None
} }
Some(Err(e)) => { Some(Err(e)) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
None None
} }
}; };
@ -1299,7 +1299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(path_bytes.len().try_into().unwrap()) Ok(path_bytes.len().try_into().unwrap())
} }
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(-1) Ok(-1)
} }
} }
@ -1382,7 +1382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(Scalar::from_maybe_pointer(dest, this)) Ok(Scalar::from_maybe_pointer(dest, this))
} }
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(Scalar::from_target_usize(0, this)) Ok(Scalar::from_target_usize(0, this))
} }
} }
@ -1503,7 +1503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => { _ => {
// "On error, -1 is returned, and errno is set to // "On error, -1 is returned, and errno is set to
// indicate the error" // indicate the error"
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
return Ok(-1); return Ok(-1);
} }
}, },
@ -1582,7 +1582,7 @@ impl FileMetadata {
let metadata = match metadata { let metadata = match metadata {
Ok(metadata) => metadata, Ok(metadata) => metadata,
Err(e) => { Err(e) => {
ecx.set_last_error_from_io_error(e.kind())?; ecx.set_last_error_from_io_error(e)?;
return Ok(None); return Ok(None);
} }
}; };

View File

@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(Scalar::from_u32(0)); return Ok(Scalar::from_u32(0));
} }
@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_path_to_wide_str(&cwd, buf, size)?, this.write_path_to_wide_str(&cwd, buf, size)?,
))); )));
} }
Err(e) => this.set_last_error_from_io_error(e.kind())?, Err(e) => this.set_last_error_from_io_error(e)?,
} }
Ok(Scalar::from_u32(0)) Ok(Scalar::from_u32(0))
} }
@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(this.eval_windows("c", "FALSE")); return Ok(this.eval_windows("c", "FALSE"));
} }
@ -193,7 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match env::set_current_dir(path) { match env::set_current_dir(path) {
Ok(()) => Ok(this.eval_windows("c", "TRUE")), Ok(()) => Ok(this.eval_windows("c", "TRUE")),
Err(e) => { Err(e) => {
this.set_last_error_from_io_error(e.kind())?; this.set_last_error_from_io_error(e)?;
Ok(this.eval_windows("c", "FALSE")) Ok(this.eval_windows("c", "FALSE"))
} }
} }

View File

@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let filename = this.read_path_from_wide_str(filename)?; let filename = this.read_path_from_wide_str(filename)?;
let result = match win_absolute(&filename)? { let result = match win_absolute(&filename)? {
Err(err) => { Err(err) => {
this.set_last_error_from_io_error(err.kind())?; this.set_last_error_from_io_error(err)?;
Scalar::from_u32(0) // return zero upon failure Scalar::from_u32(0) // return zero upon failure
} }
Ok(abs_filename) => { Ok(abs_filename) => {