From 6d14a5e2a7c17f1fec43c319cc9317ded44701ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 19:21:47 -0400 Subject: [PATCH] avoid strerror_r failure on unknown errnum --- src/helpers.rs | 11 +++++++---- src/shims/unix/foreign_items.rs | 7 +++++-- tests/pass/fs.rs | 10 ++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 8523af84d06..220347ff1b9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -609,20 +609,23 @@ fn io_error_to_errnum( } /// The inverse of `io_error_to_errnum`. - fn errnum_to_io_error( + #[allow(clippy::needless_return)] + fn try_errnum_to_io_error( &self, errnum: Scalar, - ) -> InterpResult<'tcx, std::io::ErrorKind> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { let errnum = errnum.to_i32()?; for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name)? { - return Ok(kind); + return Ok(Some(kind)); } } - throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum) + // Our table is as complete as the mapping in std, so we are okay with saying "that's a + // strange one" here. + return Ok(None); } else { throw_unsup_format!( "converting errnum into io::Error is unsupported for OS {}", diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 83815cccb0c..dc80d592a0c 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -465,8 +465,11 @@ fn emulate_foreign_item_by_name( let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; - let error = this.errnum_to_io_error(errnum)?; - let formatted = error.to_string(); + let error = this.try_errnum_to_io_error(errnum)?; + let formatted = match error { + Some(err) => format!("{err}"), + None => format!(""), + }; let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; this.write_int(ret, dest)?; diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index a8025007bf5..af9f854ce52 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] #![feature(io_error_more)] +#![feature(io_error_uncategorized)] use std::ffi::CString; use std::fs::{ @@ -26,6 +27,7 @@ fn main() { test_directory(); test_canonicalize(); test_dup_stdout_stderr(); + test_from_raw_os_error(); // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test test_file_open_unix_allow_two_args(); @@ -434,3 +436,11 @@ fn test_dup_stdout_stderr() { libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); } } + +fn test_from_raw_os_error() { + let code = 6; // not a code that std or Miri know + let error = Error::from_raw_os_error(code); + assert!(matches!(error.kind(), ErrorKind::Uncategorized)); + // Make sure we can also format this. + format!("{error:?}"); +}