@@ -345,4 +345,68 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
345345 }
346346 Ok ( ( ) )
347347 }
348+
349+ /// Sets the last error variable.
350+ fn set_last_error ( & mut self , scalar : Scalar < Tag > ) -> InterpResult < ' tcx > {
351+ let this = self . eval_context_mut ( ) ;
352+ let errno_place = this. machine . last_error . unwrap ( ) ;
353+ this. write_scalar ( scalar, errno_place. into ( ) )
354+ }
355+
356+ /// Gets the last error variable.
357+ fn get_last_error ( & mut self ) -> InterpResult < ' tcx , Scalar < Tag > > {
358+ let this = self . eval_context_mut ( ) ;
359+ let errno_place = this. machine . last_error . unwrap ( ) ;
360+ this. read_scalar ( errno_place. into ( ) ) ?. not_undef ( )
361+ }
362+
363+ /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most
364+ /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error.
365+ fn set_last_error_from_io_error ( & mut self , e : std:: io:: Error ) -> InterpResult < ' tcx > {
366+ use std:: io:: ErrorKind :: * ;
367+ let this = self . eval_context_mut ( ) ;
368+ let target = & this. tcx . tcx . sess . target . target ;
369+ let last_error = if target. options . target_family == Some ( "unix" . to_owned ( ) ) {
370+ this. eval_libc ( match e. kind ( ) {
371+ ConnectionRefused => "ECONNREFUSED" ,
372+ ConnectionReset => "ECONNRESET" ,
373+ PermissionDenied => "EPERM" ,
374+ BrokenPipe => "EPIPE" ,
375+ NotConnected => "ENOTCONN" ,
376+ ConnectionAborted => "ECONNABORTED" ,
377+ AddrNotAvailable => "EADDRNOTAVAIL" ,
378+ AddrInUse => "EADDRINUSE" ,
379+ NotFound => "ENOENT" ,
380+ Interrupted => "EINTR" ,
381+ InvalidInput => "EINVAL" ,
382+ TimedOut => "ETIMEDOUT" ,
383+ AlreadyExists => "EEXIST" ,
384+ WouldBlock => "EWOULDBLOCK" ,
385+ _ => throw_unsup_format ! ( "The {} error cannot be transformed into a raw os error" , e)
386+ } ) ?
387+ } else {
388+ // FIXME: we have to implement the windows' equivalent of this.
389+ throw_unsup_format ! ( "Setting the last OS error from an io::Error is unsupported for {}." , target. target_os)
390+ } ;
391+ this. set_last_error ( last_error)
392+ }
393+
394+ /// Helper function that consumes an `std::io::Result<T>` and returns an
395+ /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
396+ /// `Ok(-1)` and sets the last OS error accordingly.
397+ ///
398+ /// This function uses `T: From<i32>` instead of `i32` directly because some IO related
399+ /// functions return different integer types (like `read`, that returns an `i64`)
400+ fn try_unwrap_io_result < T : From < i32 > > (
401+ & mut self ,
402+ result : std:: io:: Result < T > ,
403+ ) -> InterpResult < ' tcx , T > {
404+ match result {
405+ Ok ( ok) => Ok ( ok) ,
406+ Err ( e) => {
407+ self . eval_context_mut ( ) . set_last_error_from_io_error ( e) ?;
408+ Ok ( ( -1 ) . into ( ) )
409+ }
410+ }
411+ }
348412}
0 commit comments