Skip to content

Commit

Permalink
fix: avoid stopping machine running current dir ops in isolation
Browse files Browse the repository at this point in the history
get and set current dir operations used to halt the machine by
throwing an exception in isolation mode. This change updates them to
return a dummy NotFound error instead, and keep the machine running.

I started with a custom error using `ErrorKind::Other`, but since it
can't be mapped to a raw OS error, I dropped it. NotFound kind of make
sense for get operations, but not much for set operations. But that's
the only error supported for windows currently.
  • Loading branch information
atsmtat committed May 18, 2021
1 parent 25a43c7 commit a7a6627
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 37 deletions.
93 changes: 56 additions & 37 deletions src/shims/env.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::convert::TryFrom;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{Error, ErrorKind};

use rustc_data_structures::fx::FxHashMap;
use rustc_mir::interpret::Pointer;
Expand Down Expand Up @@ -321,20 +322,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"`getcwd` is only available for the UNIX target family"
);

this.check_no_isolation("`getcwd`")?;

let buf = this.read_scalar(&buf_op)?.check_init()?;
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
// If we cannot get the current directory, we return null
match env::current_dir() {
Ok(cwd) => {
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
return Ok(buf);
if this.machine.communicate {
let buf = this.read_scalar(&buf_op)?.check_init()?;
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
// If we cannot get the current directory, we return null
match env::current_dir() {
Ok(cwd) => {
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
return Ok(buf);
}
let erange = this.eval_libc("ERANGE")?;
this.set_last_error(erange)?;
}
let erange = this.eval_libc("ERANGE")?;
this.set_last_error(erange)?;
Err(e) => this.set_last_error_from_io_error(e)?,
}
Err(e) => this.set_last_error_from_io_error(e)?,
} else {
// Emulate an error in isolation mode
let err = Error::new(ErrorKind::NotFound, "`getcwd` not available in isolation mode");
this.set_last_error_from_io_error(err)?;
}
Ok(Scalar::null_ptr(&*this.tcx))
}
Expand All @@ -348,16 +353,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
this.assert_target_os("windows", "GetCurrentDirectoryW");

this.check_no_isolation("`GetCurrentDirectoryW`")?;
if this.machine.communicate {
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
let buf = this.read_scalar(buf_op)?.check_init()?;

let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
let buf = this.read_scalar(buf_op)?.check_init()?;

// If we cannot get the current directory, we return 0
match env::current_dir() {
Ok(cwd) =>
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
Err(e) => this.set_last_error_from_io_error(e)?,
// If we cannot get the current directory, we return 0
match env::current_dir() {
Ok(cwd) =>
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
Err(e) => this.set_last_error_from_io_error(e)?,
}
} else {
// Emulate an error in isolation mode
let err = Error::new(ErrorKind::NotFound, "`GetCurrentDirectoryW` not available in isolation mode");
this.set_last_error_from_io_error(err)?;
}
Ok(0)
}
Expand All @@ -370,16 +379,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"`getcwd` is only available for the UNIX target family"
);

this.check_no_isolation("`chdir`")?;

let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;
if this.machine.communicate {
let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;

match env::set_current_dir(path) {
Ok(()) => Ok(0),
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(-1)
match env::set_current_dir(path) {
Ok(()) => Ok(0),
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(-1)
}
}
} else {
// Emulate an error in isolation mode
let err = Error::new(ErrorKind::NotFound, "`chdir` not available in isolation mode");
this.set_last_error_from_io_error(err)?;
Ok(-1)
}
}

Expand All @@ -393,16 +407,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
this.assert_target_os("windows", "SetCurrentDirectoryW");

this.check_no_isolation("`SetCurrentDirectoryW`")?;

let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;
if this.machine.communicate {
let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;

match env::set_current_dir(path) {
Ok(()) => Ok(1),
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(0)
match env::set_current_dir(path) {
Ok(()) => Ok(1),
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(0)
}
}
} else {
// Emulate an error in isolation mode
let err = Error::new(ErrorKind::NotFound, "`SetCurrentDirectoryW` not available in isolation mode");
this.set_last_error_from_io_error(err)?;
Ok(0)
}
}

Expand Down
9 changes: 9 additions & 0 deletions tests/run-pass/current_dir_with_isolation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::env;
use std::io::ErrorKind;

fn main() {
// Test that current dir operations return the dummy error instead
// of stopping the machine in isolation mode
assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound);
assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound);
}

0 comments on commit a7a6627

Please sign in to comment.