Skip to content

Commit 74c5f1b

Browse files
committed
Auto merge of rust-lang#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.
2 parents 1a87926 + 6d14a5e commit 74c5f1b

File tree

3 files changed

+22
-6
lines changed

3 files changed

+22
-6
lines changed

src/helpers.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -609,20 +609,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
609609
}
610610

611611
/// The inverse of `io_error_to_errnum`.
612-
fn errnum_to_io_error(
612+
#[allow(clippy::needless_return)]
613+
fn try_errnum_to_io_error(
613614
&self,
614615
errnum: Scalar<Provenance>,
615-
) -> InterpResult<'tcx, std::io::ErrorKind> {
616+
) -> InterpResult<'tcx, Option<std::io::ErrorKind>> {
616617
let this = self.eval_context_ref();
617618
let target = &this.tcx.sess.target;
618619
if target.families.iter().any(|f| f == "unix") {
619620
let errnum = errnum.to_i32()?;
620621
for &(name, kind) in UNIX_IO_ERROR_TABLE {
621622
if errnum == this.eval_libc_i32(name)? {
622-
return Ok(kind);
623+
return Ok(Some(kind));
623624
}
624625
}
625-
throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum)
626+
// Our table is as complete as the mapping in std, so we are okay with saying "that's a
627+
// strange one" here.
628+
return Ok(None);
626629
} else {
627630
throw_unsup_format!(
628631
"converting errnum into io::Error is unsupported for OS {}",

src/shims/unix/foreign_items.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
465465
let buf = this.read_pointer(buf)?;
466466
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
467467

468-
let error = this.errnum_to_io_error(errnum)?;
469-
let formatted = error.to_string();
468+
let error = this.try_errnum_to_io_error(errnum)?;
469+
let formatted = match error {
470+
Some(err) => format!("{err}"),
471+
None => format!("<unknown errnum in strerror_r: {errnum}>"),
472+
};
470473
let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
471474
let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? };
472475
this.write_int(ret, dest)?;

tests/pass/fs.rs

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#![feature(rustc_private)]
55
#![feature(io_error_more)]
6+
#![feature(io_error_uncategorized)]
67

78
use std::ffi::CString;
89
use std::fs::{
@@ -26,6 +27,7 @@ fn main() {
2627
test_directory();
2728
test_canonicalize();
2829
test_dup_stdout_stderr();
30+
test_from_raw_os_error();
2931

3032
// These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test
3133
test_file_open_unix_allow_two_args();
@@ -434,3 +436,11 @@ fn test_dup_stdout_stderr() {
434436
libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len());
435437
}
436438
}
439+
440+
fn test_from_raw_os_error() {
441+
let code = 6; // not a code that std or Miri know
442+
let error = Error::from_raw_os_error(code);
443+
assert!(matches!(error.kind(), ErrorKind::Uncategorized));
444+
// Make sure we can also format this.
445+
format!("{error:?}");
446+
}

0 commit comments

Comments
 (0)