From 4232939319448244bacd8376049a17325225eadb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:44:45 -0500 Subject: [PATCH 1/7] Move last error functions to helpers --- src/helpers.rs | 35 +++++++++++++++++++++++++++++++++++ src/shims/env.rs | 4 ++-- src/shims/foreign_items.rs | 28 ---------------------------- src/shims/fs.rs | 2 +- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 0c22a0f2e06..36091d92355 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -345,4 +345,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + /// Sets the last error variable + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( + tcx, + errno_ptr, + scalar.into(), + Size::from_bits(32), + ) + } + + /// Gets the last error variable + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory + .get(errno_ptr.alloc_id)? + .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .not_undef() + } + + /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be + /// transformed to a raw os error succesfully + fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().ok_or_else(|| { + err_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })?, + Size::from_bits(32), + )) + } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 6078ca26e26..661e8bf209b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.consume_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e)?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.consume_io_error(e)?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b28e361b137..5d2c3648b43 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -977,34 +977,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } - - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - // We allocated this during machine initialziation so the bounds are fine. - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - &*this.tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) - } - - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))? - .not_undef() - } - - fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - )) - } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ed2465cd1f9..8fcd5c8b1e3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -285,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().consume_io_error(e)?; + self.eval_context_mut().set_last_error_from_io_error(e)?; Ok((-1).into()) } } From ed776f67ba73380926d987bb8ba6618fa0cc55f3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:58:02 -0500 Subject: [PATCH 2/7] Change last_error to a place --- src/eval.rs | 3 +-- src/helpers.rs | 18 ++++-------------- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 3 ++- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 6fb1cd25b15..f4a8d176172 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; - let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?; - ecx.machine.last_error = errno_ptr; + ecx.machine.last_error = Some(errno_place); Ok(ecx) } diff --git a/src/helpers.rs b/src/helpers.rs index 36091d92355..1b80166b2fe 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -349,25 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Sets the last error variable fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(tcx, errno_ptr, Size::from_bits(32))? - .not_undef() + let errno_place = this.machine.last_error.unwrap(); + this.read_scalar(errno_place.into())?.not_undef() } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be diff --git a/src/machine.rs b/src/machine.rs index 3878a086053..3714aa2d799 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,8 +91,8 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error. - pub(crate) last_error: Option>, + /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + pub(crate) last_error: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5d2c3648b43..51be7ea5bcd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -414,7 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__errno_location" | "__error" => { - let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); + let errno_place = this.machine.last_error.unwrap(); + let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); this.write_scalar(errno_scalar, dest)?; } From 338e51aa48fbf9d5f3407c3872e46facfab53ca3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 16 Oct 2019 21:37:35 -0500 Subject: [PATCH 3/7] Rename consume_result --- src/helpers.rs | 19 +++++++++++++++++++ src/shims/fs.rs | 29 +++++------------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1b80166b2fe..465fca554c1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -370,4 +370,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bits(32), )) } + + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an + /// OS error using `std::io::Error::raw_os_error`. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) + fn set_last_error_from_io_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().set_last_error_from_io_error(e)?; + Ok((-1).into()) + } + } + } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8fcd5c8b1e3..c8d1eb29562 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.consume_result(fd) + this.set_last_error_from_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.consume_result(handle.file.sync_all().map(|_| 0i32)) + this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?.map(|bytes| bytes as i64)) + this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?) + this.set_last_error_from_io_result(bytes?) }) } @@ -223,7 +223,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.consume_result(result) + this.set_last_error_from_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it @@ -271,23 +271,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((-1).into()) } } - - /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) - fn consume_result>( - &mut self, - result: std::io::Result, - ) -> InterpResult<'tcx, T> { - match result { - Ok(ok) => Ok(ok), - Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; - Ok((-1).into()) - } - } - } } From 5c3c738c4b82a00471cffe67e44a22173404bd4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 20:29:30 -0500 Subject: [PATCH 4/7] Make transformation to OS error explicit --- src/helpers.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 465fca554c1..7d68d05cdb7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -361,14 +361,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully + /// transformed to a raw os error succesfully. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().ok_or_else(|| { - err_unsup_format!("The {} error cannot be transformed into a raw os error", e) - })?, - Size::from_bits(32), - )) + use std::io::ErrorKind::*; + let this = self.eval_context_mut(); + let target = &this.tcx.tcx.sess.target.target; + let last_error = if target.options.target_family == Some("unix".to_owned()) { + this.eval_libc(match e.kind() { + ConnectionRefused => "ECONNREFUSED", + ConnectionReset => "ECONNRESET", + PermissionDenied => "EPERM", + BrokenPipe => "EPIPE", + NotConnected => "ENOTCONN", + ConnectionAborted => "ECONNABORTED", + AddrNotAvailable => "EADDRNOTAVAIL", + AddrInUse => "EADDRINUSE", + NotFound => "ENOENT", + Interrupted => "EINTR", + InvalidInput => "EINVAL", + TimedOut => "ETIMEDOUT", + AlreadyExists => "EEXIST", + WouldBlock => "EWOULDBLOCK", + _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })? + } else { + // FIXME: we have to implement the windows' equivalent of this. + throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) + }; + this.set_last_error(last_error) } /// Helper function that consumes an `std::io::Result` and returns an From 619ccf3834d18eeef1aea4030e5c2bcf673e5688 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:33:25 -0500 Subject: [PATCH 5/7] Rename set_last_error_from_io_result --- src/helpers.rs | 10 +++++----- src/machine.rs | 2 +- src/shims/fs.rs | 11 +++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7d68d05cdb7..616de837879 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -360,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(errno_place.into())?.not_undef() } - /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully. + /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most + /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); @@ -392,12 +392,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. + /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns + /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related /// functions return different integer types (like `read`, that returns an `i64`) - fn set_last_error_from_io_result>( + fn try_unwrap_io_result>( &mut self, result: std::io::Result, ) -> InterpResult<'tcx, T> { diff --git a/src/machine.rs b/src/machine.rs index 3714aa2d799..315e9c1a35a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) pub(crate) last_error: Option>, /// TLS state. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c8d1eb29562..ffcfab10081 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.set_last_error_from_io_result(fd) + this.try_unwrap_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) + this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -175,9 +175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); - // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) + this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?) + this.try_unwrap_io_result(bytes?) }) } @@ -223,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.set_last_error_from_io_result(result) + this.try_unwrap_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it From 8a8fa53a5d28fa3e849e26e907480dd28b8f2aa3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:44:48 -0500 Subject: [PATCH 6/7] Transform the last error place to an immediate instead --- src/shims/foreign_items.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 51be7ea5bcd..1933aee1151 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -415,8 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" | "__error" => { let errno_place = this.machine.last_error.unwrap(); - let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); - this.write_scalar(errno_scalar, dest)?; + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } "getenv" => { From 9d50c5e75806bc27fc0b144be92b895c2f2a7339 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 14:00:44 -0500 Subject: [PATCH 7/7] Small corrections to docs --- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 616de837879..16091bb242c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,14 +346,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Sets the last error variable + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); this.write_scalar(scalar, errno_place.into()) } - /// Gets the last error variable + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); diff --git a/src/machine.rs b/src/machine.rs index 315e9c1a35a..50f0ecf5909 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32-bit integer pub(crate) last_error: Option>, /// TLS state.