Skip to content

Commit 97510cd

Browse files
committed
Auto merge of #3929 - RalfJung:io-error, r=RalfJung
Make returning io errors more uniform and convenient
2 parents c37539d + 4f4e1d4 commit 97510cd

12 files changed

Lines changed: 280 additions & 262 deletions

File tree

‎src/tools/miri/src/helpers.rs‎

Lines changed: 1 addition & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
22
use std::num::NonZero;
33
use std::sync::Mutex;
44
use std::time::Duration;
5-
use std::{cmp,io,iter};
5+
use std::{cmp, iter};
66

77
use rand::RngCore;
88
use rustc_apfloat::Float;
@@ -31,65 +31,6 @@ pub enum AccessKind {
3131
Write,
3232
}
3333

34-
// This mapping should match `decode_error_kind` in
35-
// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
36-
constUNIX_IO_ERROR_TABLE:&[(&str, std::io::ErrorKind)] = {
37-
use std::io::ErrorKind::*;
38-
&[
39-
("E2BIG",ArgumentListTooLong),
40-
("EADDRINUSE",AddrInUse),
41-
("EADDRNOTAVAIL",AddrNotAvailable),
42-
("EBUSY",ResourceBusy),
43-
("ECONNABORTED",ConnectionAborted),
44-
("ECONNREFUSED",ConnectionRefused),
45-
("ECONNRESET",ConnectionReset),
46-
("EDEADLK",Deadlock),
47-
("EDQUOT",FilesystemQuotaExceeded),
48-
("EEXIST",AlreadyExists),
49-
("EFBIG",FileTooLarge),
50-
("EHOSTUNREACH",HostUnreachable),
51-
("EINTR",Interrupted),
52-
("EINVAL",InvalidInput),
53-
("EISDIR",IsADirectory),
54-
("ELOOP",FilesystemLoop),
55-
("ENOENT",NotFound),
56-
("ENOMEM",OutOfMemory),
57-
("ENOSPC",StorageFull),
58-
("ENOSYS",Unsupported),
59-
("EMLINK",TooManyLinks),
60-
("ENAMETOOLONG",InvalidFilename),
61-
("ENETDOWN",NetworkDown),
62-
("ENETUNREACH",NetworkUnreachable),
63-
("ENOTCONN",NotConnected),
64-
("ENOTDIR",NotADirectory),
65-
("ENOTEMPTY",DirectoryNotEmpty),
66-
("EPIPE",BrokenPipe),
67-
("EROFS",ReadOnlyFilesystem),
68-
("ESPIPE",NotSeekable),
69-
("ESTALE",StaleNetworkFileHandle),
70-
("ETIMEDOUT",TimedOut),
71-
("ETXTBSY",ExecutableFileBusy),
72-
("EXDEV",CrossesDevices),
73-
// The following have two valid options. We have both for the forwards mapping; only the
74-
// first one will be used for the backwards mapping.
75-
("EPERM",PermissionDenied),
76-
("EACCES",PermissionDenied),
77-
("EWOULDBLOCK",WouldBlock),
78-
("EAGAIN",WouldBlock),
79-
]
80-
};
81-
// This mapping should match `decode_error_kind` in
82-
// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/windows/mod.rs>.
83-
constWINDOWS_IO_ERROR_TABLE:&[(&str, std::io::ErrorKind)] = {
84-
use std::io::ErrorKind::*;
85-
// FIXME: this is still incomplete.
86-
&[
87-
("ERROR_ACCESS_DENIED",PermissionDenied),
88-
("ERROR_FILE_NOT_FOUND",NotFound),
89-
("ERROR_INVALID_PARAMETER",InvalidInput),
90-
]
91-
};
92-
9334
/// Gets an instance for a path.
9435
///
9536
/// A `None` namespace indicates we are looking for a module.
@@ -745,130 +686,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
745686
self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
746687
}
747688

748-
/// Get last error variable as a place, lazily allocating thread-local storage for it if
749-
/// necessary.
750-
fnlast_error_place(&mutself) -> InterpResult<'tcx,MPlaceTy<'tcx>>{
751-
let this = self.eval_context_mut();
752-
ifletSome(errno_place) = this.active_thread_ref().last_error.as_ref(){
753-
Ok(errno_place.clone())
754-
}else{
755-
// Allocate new place, set initial value to 0.
756-
let errno_layout = this.machine.layouts.u32;
757-
let errno_place = this.allocate(errno_layout,MiriMemoryKind::Machine.into())?;
758-
this.write_scalar(Scalar::from_u32(0),&errno_place)?;
759-
this.active_thread_mut().last_error = Some(errno_place.clone());
760-
Ok(errno_place)
761-
}
762-
}
763-
764-
/// Sets the last error variable.
765-
fnset_last_error(&mutself,scalar:Scalar) -> InterpResult<'tcx>{
766-
let this = self.eval_context_mut();
767-
let errno_place = this.last_error_place()?;
768-
this.write_scalar(scalar,&errno_place)
769-
}
770-
771-
/// Gets the last error variable.
772-
fnget_last_error(&mutself) -> InterpResult<'tcx,Scalar>{
773-
let this = self.eval_context_mut();
774-
let errno_place = this.last_error_place()?;
775-
this.read_scalar(&errno_place)
776-
}
777-
778-
/// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
779-
/// as a platform-specific errnum.
780-
fnio_error_to_errnum(&self,err: std::io::Error) -> InterpResult<'tcx,Scalar>{
781-
let this = self.eval_context_ref();
782-
let target = &this.tcx.sess.target;
783-
if target.families.iter().any(|f| f == "unix"){
784-
for&(name, kind)inUNIX_IO_ERROR_TABLE{
785-
if err.kind() == kind {
786-
returnOk(this.eval_libc(name));
787-
}
788-
}
789-
throw_unsup_format!("unsupported io error: {err}")
790-
}elseif target.families.iter().any(|f| f == "windows"){
791-
for&(name, kind)inWINDOWS_IO_ERROR_TABLE{
792-
if err.kind() == kind {
793-
returnOk(this.eval_windows("c", name));
794-
}
795-
}
796-
throw_unsup_format!("unsupported io error: {err}");
797-
}else{
798-
throw_unsup_format!(
799-
"converting io::Error into errnum is unsupported for OS {}",
800-
target.os
801-
)
802-
}
803-
}
804-
805-
/// The inverse of `io_error_to_errnum`.
806-
#[allow(clippy::needless_return)]
807-
fntry_errnum_to_io_error(
808-
&self,
809-
errnum:Scalar,
810-
) -> InterpResult<'tcx,Option<std::io::ErrorKind>>{
811-
let this = self.eval_context_ref();
812-
let target = &this.tcx.sess.target;
813-
if target.families.iter().any(|f| f == "unix"){
814-
let errnum = errnum.to_i32()?;
815-
for&(name, kind)inUNIX_IO_ERROR_TABLE{
816-
if errnum == this.eval_libc_i32(name){
817-
returnOk(Some(kind));
818-
}
819-
}
820-
returnOk(None);
821-
}elseif target.families.iter().any(|f| f == "windows"){
822-
let errnum = errnum.to_u32()?;
823-
for&(name, kind)inWINDOWS_IO_ERROR_TABLE{
824-
if errnum == this.eval_windows("c", name).to_u32()? {
825-
returnOk(Some(kind));
826-
}
827-
}
828-
returnOk(None);
829-
}else{
830-
throw_unsup_format!(
831-
"converting errnum into io::Error is unsupported for OS {}",
832-
target.os
833-
)
834-
}
835-
}
836-
837-
/// Sets the last OS error using a `std::io::ErrorKind`.
838-
fnset_last_error_from_io_error(&mutself,err: std::io::Error) -> InterpResult<'tcx>{
839-
self.set_last_error(self.io_error_to_errnum(err)?)
840-
}
841-
842-
/// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place.
843-
fnset_last_error_and_return(
844-
&mutself,
845-
err:implInto<io::Error>,
846-
dest:&MPlaceTy<'tcx>,
847-
) -> InterpResult<'tcx>{
848-
self.set_last_error(self.io_error_to_errnum(err.into())?)?;
849-
self.write_int(-1, dest)?;
850-
Ok(())
851-
}
852-
853-
/// Helper function that consumes an `std::io::Result<T>` and returns an
854-
/// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
855-
/// `Ok(-1)` and sets the last OS error accordingly.
856-
///
857-
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
858-
/// functions return different integer types (like `read`, that returns an `i64`).
859-
fntry_unwrap_io_result<T:From<i32>>(
860-
&mutself,
861-
result: std::io::Result<T>,
862-
) -> InterpResult<'tcx,T>{
863-
match result {
864-
Ok(ok) => Ok(ok),
865-
Err(e) => {
866-
self.eval_context_mut().set_last_error_from_io_error(e)?;
867-
Ok((-1).into())
868-
}
869-
}
870-
}
871-
872689
/// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
873690
fnderef_pointer_as(
874691
&self,

‎src/tools/miri/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ pub use crate::range_map::RangeMap;
150150
pubusecrate::shims::EmulateItemResult;
151151
pubusecrate::shims::env::{EnvVars,EvalContextExtas _};
152152
pubusecrate::shims::foreign_items::{DynSym,EvalContextExtas _};
153+
pubusecrate::shims::io_error::{EvalContextExtas _,LibcError};
153154
pubusecrate::shims::os_str::EvalContextExtas _;
154155
pubusecrate::shims::panic::{CatchUnwindData,EvalContextExtas _};
155156
pubusecrate::shims::time::EvalContextExtas _;

0 commit comments

Comments
 (0)