@@ -21,6 +21,27 @@ use crate::*;
21
21
22
22
impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
23
23
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
+
24
45
/// Gets an instance for a path.
25
46
fn try_resolve_did < ' mir , ' tcx > ( tcx : TyCtxt < ' tcx > , path : & [ & str ] ) -> Option < DefId > {
26
47
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
502
523
this. read_scalar ( & errno_place. into ( ) ) ?. check_init ( )
503
524
}
504
525
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 ( ) ;
510
530
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) ;
534
535
}
535
- } ) ?
536
+ }
537
+ throw_unsup_format ! ( "io error {:?} cannot be translated into a raw os error" , err_kind)
536
538
} else if target. families . iter ( ) . any ( |f| f == "windows" ) {
537
539
// FIXME: we have to finish implementing the Windows equivalent of this.
540
+ use std:: io:: ErrorKind :: * ;
538
541
this. eval_windows (
539
542
"c" ,
540
543
match err_kind {
@@ -546,14 +549,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
546
549
err_kind
547
550
) ,
548
551
} ,
549
- ) ?
552
+ )
550
553
} else {
551
554
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
554
557
)
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) ?)
557
584
}
558
585
559
586
/// Helper function that consumes an `std::io::Result<T>` and returns an
0 commit comments