Skip to content

Commit 827c42e

Browse files
committed
fix: avoid stopping machine running current dir ops in isolation
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.
1 parent bcae331 commit 827c42e

File tree

2 files changed

+65
-37
lines changed

2 files changed

+65
-37
lines changed

src/shims/env.rs

+56-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::ffi::{OsString, OsStr};
22
use std::env;
3+
use std::io::{Error, ErrorKind};
34
use std::convert::TryFrom;
45

56
use rustc_target::abi::{Size, LayoutOf};
@@ -293,20 +294,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
293294
let target_os = &this.tcx.sess.target.os;
294295
assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family");
295296

296-
this.check_no_isolation("`getcwd`")?;
297-
298-
let buf = this.read_scalar(&buf_op)?.check_init()?;
299-
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
300-
// If we cannot get the current directory, we return null
301-
match env::current_dir() {
302-
Ok(cwd) => {
303-
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
304-
return Ok(buf);
297+
if this.machine.communicate {
298+
let buf = this.read_scalar(&buf_op)?.check_init()?;
299+
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
300+
// If we cannot get the current directory, we return null
301+
match env::current_dir() {
302+
Ok(cwd) => {
303+
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
304+
return Ok(buf);
305+
}
306+
let erange = this.eval_libc("ERANGE")?;
307+
this.set_last_error(erange)?;
305308
}
306-
let erange = this.eval_libc("ERANGE")?;
307-
this.set_last_error(erange)?;
309+
Err(e) => this.set_last_error_from_io_error(e)?,
308310
}
309-
Err(e) => this.set_last_error_from_io_error(e)?,
311+
} else {
312+
// Emulate an error in isolation mode
313+
let err = Error::new(ErrorKind::NotFound, "`getcwd` not available in isolation mode");
314+
this.set_last_error_from_io_error(err)?;
310315
}
311316
Ok(Scalar::null_ptr(&*this.tcx))
312317
}
@@ -320,16 +325,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
320325
let this = self.eval_context_mut();
321326
this.assert_target_os("windows", "GetCurrentDirectoryW");
322327

323-
this.check_no_isolation("`GetCurrentDirectoryW`")?;
328+
if this.machine.communicate {
329+
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
330+
let buf = this.read_scalar(buf_op)?.check_init()?;
324331

325-
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
326-
let buf = this.read_scalar(buf_op)?.check_init()?;
327-
328-
// If we cannot get the current directory, we return 0
329-
match env::current_dir() {
330-
Ok(cwd) =>
331-
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
332-
Err(e) => this.set_last_error_from_io_error(e)?,
332+
// If we cannot get the current directory, we return 0
333+
match env::current_dir() {
334+
Ok(cwd) =>
335+
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
336+
Err(e) => this.set_last_error_from_io_error(e)?,
337+
}
338+
} else {
339+
// Emulate an error in isolation mode
340+
let err = Error::new(ErrorKind::NotFound, "`GetCurrentDirectoryW` not available in isolation mode");
341+
this.set_last_error_from_io_error(err)?;
333342
}
334343
Ok(0)
335344
}
@@ -339,16 +348,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
339348
let target_os = &this.tcx.sess.target.os;
340349
assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family");
341350

342-
this.check_no_isolation("`chdir`")?;
343-
344-
let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;
351+
if this.machine.communicate {
352+
let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;
345353

346-
match env::set_current_dir(path) {
347-
Ok(()) => Ok(0),
348-
Err(e) => {
349-
this.set_last_error_from_io_error(e)?;
350-
Ok(-1)
354+
match env::set_current_dir(path) {
355+
Ok(()) => Ok(0),
356+
Err(e) => {
357+
this.set_last_error_from_io_error(e)?;
358+
Ok(-1)
359+
}
351360
}
361+
} else {
362+
// Emulate an error in isolation mode
363+
let err = Error::new(ErrorKind::NotFound, "`chdir` not available in isolation mode");
364+
this.set_last_error_from_io_error(err)?;
365+
Ok(-1)
352366
}
353367
}
354368

@@ -360,16 +374,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
360374
let this = self.eval_context_mut();
361375
this.assert_target_os("windows", "SetCurrentDirectoryW");
362376

363-
this.check_no_isolation("`SetCurrentDirectoryW`")?;
364-
365-
let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;
377+
if this.machine.communicate {
378+
let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;
366379

367-
match env::set_current_dir(path) {
368-
Ok(()) => Ok(1),
369-
Err(e) => {
370-
this.set_last_error_from_io_error(e)?;
371-
Ok(0)
380+
match env::set_current_dir(path) {
381+
Ok(()) => Ok(1),
382+
Err(e) => {
383+
this.set_last_error_from_io_error(e)?;
384+
Ok(0)
385+
}
372386
}
387+
} else {
388+
// Emulate an error in isolation mode
389+
let err = Error::new(ErrorKind::NotFound, "`SetCurrentDirectoryW` not available in isolation mode");
390+
this.set_last_error_from_io_error(err)?;
391+
Ok(0)
373392
}
374393
}
375394

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::env;
2+
use std::io::ErrorKind;
3+
4+
fn main() {
5+
// Test that current dir operations return the dummy error instead
6+
// of stopping the machine in isolation mode
7+
assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound);
8+
assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound);
9+
}

0 commit comments

Comments
 (0)