Skip to content

Commit cf0e1e0

Browse files
committed
Enable close-ing stdin/stdout/stderr
1 parent 339a3ca commit cf0e1e0

File tree

5 files changed

+78
-21
lines changed

5 files changed

+78
-21
lines changed

src/shims/posix/fs.rs

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ trait FileDescriptor : std::fmt::Debug {
2828
fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>>;
2929
fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>>;
3030
fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>>;
31+
fn close<'tcx>(&mut self, communicate_allowed: bool) -> InterpResult<'tcx, io::Result<i32>>;
3132
}
3233

3334
impl FileDescriptor for FileHandle {
@@ -49,6 +50,29 @@ impl FileDescriptor for FileHandle {
4950
assert!(communicate_allowed, "isolation should have prevented even opening a file");
5051
Ok(self.file.seek(offset))
5152
}
53+
54+
fn close<'tcx>(&mut self, communicate_allowed: bool) -> InterpResult<'tcx, io::Result<i32>> {
55+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
56+
// We sync the file if it was opened in a mode different than read-only.
57+
if self.writable {
58+
// `File::sync_all` does the checks that are done when closing a file. We do this to
59+
// to handle possible errors correctly.
60+
let result = self.file.sync_all().map(|_| 0i32);
61+
// Now we actually close the file.
62+
drop(self);
63+
// And return the result.
64+
Ok(result)
65+
} else {
66+
// We drop the file, this closes it but ignores any errors
67+
// produced when closing it. This is done because
68+
// `File::sync_all` cannot be done over files like
69+
// `/dev/urandom` which are read-only. Check
70+
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
71+
// for a deeper discussion.
72+
drop(self);
73+
Ok(Ok(0))
74+
}
75+
}
5276
}
5377

5478
impl FileDescriptor for io::Stdin {
@@ -71,6 +95,11 @@ impl FileDescriptor for io::Stdin {
7195
fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
7296
throw_unsup_format!("cannot seek on stdin");
7397
}
98+
99+
fn close<'tcx>(&mut self, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result<i32>> {
100+
drop(io::stdin());
101+
Ok(Ok(0))
102+
}
74103
}
75104

76105
impl FileDescriptor for io::Stdout {
@@ -98,6 +127,11 @@ impl FileDescriptor for io::Stdout {
98127
fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
99128
throw_unsup_format!("cannot seek on stdout");
100129
}
130+
131+
fn close<'tcx>(&mut self, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result<i32>> {
132+
drop(io::stdout());
133+
Ok(Ok(0))
134+
}
101135
}
102136

103137
impl FileDescriptor for io::Stderr {
@@ -118,6 +152,11 @@ impl FileDescriptor for io::Stderr {
118152
fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
119153
throw_unsup_format!("cannot seek on stderr");
120154
}
155+
156+
fn close<'tcx>(&mut self, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result<i32>> {
157+
drop(io::stderr());
158+
Ok(Ok(0))
159+
}
121160
}
122161

123162
#[derive(Debug)]
@@ -539,27 +578,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
539578

540579
let fd = this.read_scalar(fd_op)?.to_i32()?;
541580

542-
if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) {
543-
// FIXME: Support `close` for all FDs(stdin, etc)
544-
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
545-
// We sync the file if it was opened in a mode different than read-only.
546-
if *writable {
547-
// `File::sync_all` does the checks that are done when closing a file. We do this to
548-
// to handle possible errors correctly.
549-
let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32));
550-
// Now we actually close the file.
551-
drop(file);
552-
// And return the result.
553-
result
554-
} else {
555-
// We drop the file, this closes it but ignores any errors produced when closing
556-
// it. This is done because `File::sync_all` cannot be done over files like
557-
// `/dev/urandom` which are read-only. Check
558-
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper
559-
// discussion.
560-
drop(file);
561-
Ok(0)
562-
}
581+
if let Some(mut file_descriptor) = this.machine.file_handler.handles.remove(&fd) {
582+
let result = file_descriptor.close(this.machine.communicate)?
583+
.map(|c| i32::try_from(c).unwrap());
584+
585+
this.try_unwrap_io_result(result)
563586
} else {
564587
this.handle_not_found()
565588
}

tests/run-pass/close-stderr.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags: -Zmiri-disable-isolation
2+
3+
#![feature(rustc_private)]
4+
5+
extern crate libc;
6+
7+
fn main() -> std::io::Result<()> {
8+
let bytes = b"hello\n";
9+
unsafe {
10+
libc::write(2, bytes.as_ptr() as *const libc::c_void, 6);
11+
libc::close(2);
12+
libc::write(2, bytes.as_ptr() as *const libc::c_void, 6);
13+
}
14+
15+
Ok(())
16+
}

tests/run-pass/close-stderr.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello

tests/run-pass/close-stdout.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags: -Zmiri-disable-isolation
2+
3+
#![feature(rustc_private)]
4+
5+
extern crate libc;
6+
7+
fn main() -> std::io::Result<()> {
8+
let bytes = b"hello\n";
9+
unsafe {
10+
libc::write(1, bytes.as_ptr() as *const libc::c_void, 6);
11+
libc::close(1);
12+
libc::write(1, bytes.as_ptr() as *const libc::c_void, 6);
13+
}
14+
15+
Ok(())
16+
}

tests/run-pass/close-stdout.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello

0 commit comments

Comments
 (0)