@@ -21,6 +21,27 @@ use crate::*;
2121
2222impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
2323
24+ const UNIX_IO_ERROR_TABLE : & [ ( std:: io:: ErrorKind , & str ) ] = {
25+ use std:: io:: ErrorKind :: * ;
26+ & [
27+ ( ConnectionRefused , "ECONNREFUSED" ) ,
28+ ( ConnectionReset , "ECONNRESET" ) ,
29+ ( PermissionDenied , "EPERM" ) ,
30+ ( BrokenPipe , "EPIPE" ) ,
31+ ( NotConnected , "ENOTCONN" ) ,
32+ ( ConnectionAborted , "ECONNABORTED" ) ,
33+ ( AddrNotAvailable , "EADDRNOTAVAIL" ) ,
34+ ( AddrInUse , "EADDRINUSE" ) ,
35+ ( NotFound , "ENOENT" ) ,
36+ ( Interrupted , "EINTR" ) ,
37+ ( InvalidInput , "EINVAL" ) ,
38+ ( TimedOut , "ETIMEDOUT" ) ,
39+ ( AlreadyExists , "EEXIST" ) ,
40+ ( WouldBlock , "EWOULDBLOCK" ) ,
41+ ( DirectoryNotEmpty , "ENOTEMPTY" ) ,
42+ ]
43+ } ;
44+
2445/// Gets an instance for a path.
2546fn try_resolve_did < ' mir , ' tcx > ( tcx : TyCtxt < ' tcx > , path : & [ & str ] ) -> Option < DefId > {
2647 tcx. crates ( ( ) ) . iter ( ) . find ( |& & krate| tcx. crate_name ( krate) . as_str ( ) == path[ 0 ] ) . and_then (
@@ -502,39 +523,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
502523 this. read_scalar ( & errno_place. into ( ) ) ?. check_init ( )
503524 }
504525
505- /// Sets the last OS error using a `std::io::ErrorKind`. This function tries to produce the most
506- /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error.
507- fn set_last_error_from_io_error ( & mut self , err_kind : std:: io:: ErrorKind ) -> InterpResult < ' tcx > {
508- use std:: io:: ErrorKind :: * ;
509- let this = self . eval_context_mut ( ) ;
526+ /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
527+ /// as a platform-specific errnum.
528+ fn io_error_to_errnum ( & self , err_kind : std:: io:: ErrorKind ) -> InterpResult < ' tcx , Scalar < Tag > > {
529+ let this = self . eval_context_ref ( ) ;
510530 let target = & this. tcx . sess . target ;
511- let target_os = & target. os ;
512- let last_error = if target. families . iter ( ) . any ( |f| f == "unix" ) {
513- this. eval_libc ( match err_kind {
514- ConnectionRefused => "ECONNREFUSED" ,
515- ConnectionReset => "ECONNRESET" ,
516- PermissionDenied => "EPERM" ,
517- BrokenPipe => "EPIPE" ,
518- NotConnected => "ENOTCONN" ,
519- ConnectionAborted => "ECONNABORTED" ,
520- AddrNotAvailable => "EADDRNOTAVAIL" ,
521- AddrInUse => "EADDRINUSE" ,
522- NotFound => "ENOENT" ,
523- Interrupted => "EINTR" ,
524- InvalidInput => "EINVAL" ,
525- TimedOut => "ETIMEDOUT" ,
526- AlreadyExists => "EEXIST" ,
527- WouldBlock => "EWOULDBLOCK" ,
528- DirectoryNotEmpty => "ENOTEMPTY" ,
529- _ => {
530- throw_unsup_format ! (
531- "io error {:?} cannot be translated into a raw os error" ,
532- err_kind
533- )
531+ if target. families . iter ( ) . any ( |f| f == "unix" ) {
532+ for & ( kind, name) in UNIX_IO_ERROR_TABLE {
533+ if err_kind == kind {
534+ return this. eval_libc ( name) ;
534535 }
535- } ) ?
536+ }
537+ throw_unsup_format ! ( "io error {:?} cannot be translated into a raw os error" , err_kind)
536538 } else if target. families . iter ( ) . any ( |f| f == "windows" ) {
537539 // FIXME: we have to finish implementing the Windows equivalent of this.
540+ use std:: io:: ErrorKind :: * ;
538541 this. eval_windows (
539542 "c" ,
540543 match err_kind {
@@ -546,14 +549,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
546549 err_kind
547550 ) ,
548551 } ,
549- ) ?
552+ )
550553 } else {
551554 throw_unsup_format ! (
552- "setting the last OS error from an io::Error is unsupported for {}. " ,
553- target_os
555+ "converting io::Error into errnum is unsupported for OS {} " ,
556+ target . os
554557 )
555- } ;
556- this. set_last_error ( last_error)
558+ }
559+ }
560+
561+ /// The inverse of `io_error_to_errnum`.
562+ fn errnum_to_io_error ( & self , errnum : Scalar < Tag > ) -> InterpResult < ' tcx , std:: io:: ErrorKind > {
563+ let this = self . eval_context_ref ( ) ;
564+ let target = & this. tcx . sess . target ;
565+ if target. families . iter ( ) . any ( |f| f == "unix" ) {
566+ let errnum = errnum. to_i32 ( ) ?;
567+ for & ( kind, name) in UNIX_IO_ERROR_TABLE {
568+ if errnum == this. eval_libc_i32 ( name) ? {
569+ return Ok ( kind) ;
570+ }
571+ }
572+ throw_unsup_format ! ( "raw errnum {:?} cannot be translated into io::Error" , errnum)
573+ } else {
574+ throw_unsup_format ! (
575+ "converting errnum into io::Error is unsupported for OS {}" ,
576+ target. os
577+ )
578+ }
579+ }
580+
581+ /// Sets the last OS error using a `std::io::ErrorKind`.
582+ fn set_last_error_from_io_error ( & mut self , err_kind : std:: io:: ErrorKind ) -> InterpResult < ' tcx > {
583+ self . set_last_error ( self . io_error_to_errnum ( err_kind) ?)
557584 }
558585
559586 /// Helper function that consumes an `std::io::Result<T>` and returns an
0 commit comments