Auto merge of #2465 - RalfJung:strerror_r, r=RalfJung

avoid strerror_r failure on unknown errnum

This is an informative function anyway, so as fallback just return a string with the raw errnum. Avoids panics / interpreter aborts in std on unknown errnum in from_raw_os_error.
This commit is contained in:
bors 2022-08-06 00:19:08 +00:00
commit 74c5f1b468
3 changed files with 22 additions and 6 deletions

View File

@ -609,20 +609,23 @@ fn io_error_to_errnum(
} }
/// The inverse of `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, &self,
errnum: Scalar<Provenance>, errnum: Scalar<Provenance>,
) -> InterpResult<'tcx, std::io::ErrorKind> { ) -> InterpResult<'tcx, Option<std::io::ErrorKind>> {
let this = self.eval_context_ref(); let this = self.eval_context_ref();
let target = &this.tcx.sess.target; let target = &this.tcx.sess.target;
if target.families.iter().any(|f| f == "unix") { if target.families.iter().any(|f| f == "unix") {
let errnum = errnum.to_i32()?; let errnum = errnum.to_i32()?;
for &(name, kind) in UNIX_IO_ERROR_TABLE { for &(name, kind) in UNIX_IO_ERROR_TABLE {
if errnum == this.eval_libc_i32(name)? { 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 { } else {
throw_unsup_format!( throw_unsup_format!(
"converting errnum into io::Error is unsupported for OS {}", "converting errnum into io::Error is unsupported for OS {}",

View File

@ -465,8 +465,11 @@ fn emulate_foreign_item_by_name(
let buf = this.read_pointer(buf)?; let buf = this.read_pointer(buf)?;
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
let error = this.errnum_to_io_error(errnum)?; let error = this.try_errnum_to_io_error(errnum)?;
let formatted = error.to_string(); let formatted = match error {
Some(err) => format!("{err}"),
None => format!("<unknown errnum in strerror_r: {errnum}>"),
};
let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; 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")? }; let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? };
this.write_int(ret, dest)?; this.write_int(ret, dest)?;

View File

@ -3,6 +3,7 @@
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(io_error_more)] #![feature(io_error_more)]
#![feature(io_error_uncategorized)]
use std::ffi::CString; use std::ffi::CString;
use std::fs::{ use std::fs::{
@ -26,6 +27,7 @@ fn main() {
test_directory(); test_directory();
test_canonicalize(); test_canonicalize();
test_dup_stdout_stderr(); 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 // 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(); 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()); 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:?}");
}