Skip to content

Commit a7a6627

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 25a43c7 commit a7a6627

File tree

2 files changed

+65
-37
lines changed

2 files changed

+65
-37
lines changed

src/shims/env.rs

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::convert::TryFrom;
22
use std::env;
33
use std::ffi::{OsStr, OsString};
4+
use std::io::{Error, ErrorKind};
45

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

324-
this.check_no_isolation("`getcwd`")?;
325-
326-
let buf = this.read_scalar(&buf_op)?.check_init()?;
327-
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
328-
// If we cannot get the current directory, we return null
329-
match env::current_dir() {
330-
Ok(cwd) => {
331-
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
332-
return Ok(buf);
325+
if this.machine.communicate {
326+
let buf = this.read_scalar(&buf_op)?.check_init()?;
327+
let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?;
328+
// If we cannot get the current directory, we return null
329+
match env::current_dir() {
330+
Ok(cwd) => {
331+
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
332+
return Ok(buf);
333+
}
334+
let erange = this.eval_libc("ERANGE")?;
335+
this.set_last_error(erange)?;
333336
}
334-
let erange = this.eval_libc("ERANGE")?;
335-
this.set_last_error(erange)?;
337+
Err(e) => this.set_last_error_from_io_error(e)?,
336338
}
337-
Err(e) => this.set_last_error_from_io_error(e)?,
339+
} else {
340+
// Emulate an error in isolation mode
341+
let err = Error::new(ErrorKind::NotFound, "`getcwd` not available in isolation mode");
342+
this.set_last_error_from_io_error(err)?;
338343
}
339344
Ok(Scalar::null_ptr(&*this.tcx))
340345
}
@@ -348,16 +353,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
348353
let this = self.eval_context_mut();
349354
this.assert_target_os("windows", "GetCurrentDirectoryW");
350355

351-
this.check_no_isolation("`GetCurrentDirectoryW`")?;
356+
if this.machine.communicate {
357+
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
358+
let buf = this.read_scalar(buf_op)?.check_init()?;
352359

353-
let size = u64::from(this.read_scalar(size_op)?.to_u32()?);
354-
let buf = this.read_scalar(buf_op)?.check_init()?;
355-
356-
// If we cannot get the current directory, we return 0
357-
match env::current_dir() {
358-
Ok(cwd) =>
359-
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
360-
Err(e) => this.set_last_error_from_io_error(e)?,
360+
// If we cannot get the current directory, we return 0
361+
match env::current_dir() {
362+
Ok(cwd) =>
363+
return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)),
364+
Err(e) => this.set_last_error_from_io_error(e)?,
365+
}
366+
} else {
367+
// Emulate an error in isolation mode
368+
let err = Error::new(ErrorKind::NotFound, "`GetCurrentDirectoryW` not available in isolation mode");
369+
this.set_last_error_from_io_error(err)?;
361370
}
362371
Ok(0)
363372
}
@@ -370,16 +379,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
370379
"`getcwd` is only available for the UNIX target family"
371380
);
372381

373-
this.check_no_isolation("`chdir`")?;
374-
375-
let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;
382+
if this.machine.communicate {
383+
let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?;
376384

377-
match env::set_current_dir(path) {
378-
Ok(()) => Ok(0),
379-
Err(e) => {
380-
this.set_last_error_from_io_error(e)?;
381-
Ok(-1)
385+
match env::set_current_dir(path) {
386+
Ok(()) => Ok(0),
387+
Err(e) => {
388+
this.set_last_error_from_io_error(e)?;
389+
Ok(-1)
390+
}
382391
}
392+
} else {
393+
// Emulate an error in isolation mode
394+
let err = Error::new(ErrorKind::NotFound, "`chdir` not available in isolation mode");
395+
this.set_last_error_from_io_error(err)?;
396+
Ok(-1)
383397
}
384398
}
385399

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

396-
this.check_no_isolation("`SetCurrentDirectoryW`")?;
397-
398-
let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;
410+
if this.machine.communicate {
411+
let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?;
399412

400-
match env::set_current_dir(path) {
401-
Ok(()) => Ok(1),
402-
Err(e) => {
403-
this.set_last_error_from_io_error(e)?;
404-
Ok(0)
413+
match env::set_current_dir(path) {
414+
Ok(()) => Ok(1),
415+
Err(e) => {
416+
this.set_last_error_from_io_error(e)?;
417+
Ok(0)
418+
}
405419
}
420+
} else {
421+
// Emulate an error in isolation mode
422+
let err = Error::new(ErrorKind::NotFound, "`SetCurrentDirectoryW` not available in isolation mode");
423+
this.set_last_error_from_io_error(err)?;
424+
Ok(0)
406425
}
407426
}
408427

Lines changed: 9 additions & 0 deletions
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)