Skip to content

Commit 1ae7b8b

Browse files
authored
Try #897:
2 parents 77527c2 + 3a87edc commit 1ae7b8b

File tree

9 files changed

+324
-31
lines changed

9 files changed

+324
-31
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Blocks of changes will separated by version increments.
66

77
## **[Unreleased]**
88

9+
- [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on.
910
- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend.
1011

1112
## 0.8.0 - 2019-10-02
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// !!! THIS IS A GENERATED FILE !!!
2+
// ANY MANUAL EDITS MAY BE OVERWRITTEN AT ANY TIME
3+
// Files autogenerated with cargo build (build/wasitests.rs).
4+
5+
#[test]
6+
fn test_fd_close() {
7+
assert_wasi_output!(
8+
"../../wasitests/fd_close.wasm",
9+
"fd_close",
10+
vec![],
11+
vec![(
12+
".".to_string(),
13+
::std::path::PathBuf::from("wasitests/test_fs/hamlet")
14+
),],
15+
vec![],
16+
"../../wasitests/fd_close.out"
17+
);
18+
}

lib/wasi-tests/tests/wasitests/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod close_preopen_fd;
99
mod create_dir;
1010
mod envvar;
1111
mod fd_allocate;
12+
mod fd_close;
1213
mod fd_pread;
1314
mod fd_read;
1415
mod fd_sync;

lib/wasi-tests/wasitests/fd_close.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Successfully closed stderr!
2+
Successfully closed stdin!

lib/wasi-tests/wasitests/fd_close.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Args:
2+
// mapdir: .:wasitests/test_fs/hamlet
3+
4+
use std::fs;
5+
#[cfg(target_os = "wasi")]
6+
use std::os::wasi::prelude::AsRawFd;
7+
use std::path::PathBuf;
8+
9+
#[cfg(target_os = "wasi")]
10+
#[link(wasm_import_module = "wasi_unstable")]
11+
extern "C" {
12+
fn fd_close(fd: u32) -> u16;
13+
}
14+
15+
fn main() {
16+
#[cfg(not(target_os = "wasi"))]
17+
let mut base = PathBuf::from("wasitests/test_fs/hamlet");
18+
#[cfg(target_os = "wasi")]
19+
let mut base = PathBuf::from(".");
20+
21+
base.push("act3/scene3.txt");
22+
let file = fs::File::open(&base).expect("could not open file");
23+
24+
#[cfg(target_os = "wasi")]
25+
{
26+
let stdout_fd = std::io::stdout().as_raw_fd();
27+
let stderr_fd = std::io::stderr().as_raw_fd();
28+
let stdin_fd = std::io::stdin().as_raw_fd();
29+
30+
let result = unsafe { fd_close(stderr_fd) };
31+
if result == 0 {
32+
println!("Successfully closed stderr!")
33+
} else {
34+
println!("Could not close stderr");
35+
}
36+
let result = unsafe { fd_close(stdin_fd) };
37+
if result == 0 {
38+
println!("Successfully closed stdin!")
39+
} else {
40+
println!("Could not close stdin");
41+
}
42+
let result = unsafe { fd_close(stdout_fd) };
43+
if result == 0 {
44+
println!("Successfully closed stdout!")
45+
} else {
46+
println!("Could not close stdout");
47+
}
48+
}
49+
#[cfg(not(target_os = "wasi"))]
50+
{
51+
println!("Successfully closed stderr!");
52+
println!("Successfully closed stdin!");
53+
}
54+
}
81 KB
Binary file not shown.

lib/wasi/src/state/mod.rs

+174-22
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ use wasmer_runtime_core::{debug, vm::Ctx};
3737
pub const VIRTUAL_ROOT_FD: __wasi_fd_t = 3;
3838
/// all the rights enabled
3939
pub const ALL_RIGHTS: __wasi_rights_t = 0x1FFFFFFF;
40+
const STDIN_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
41+
| __WASI_RIGHT_FD_READ
42+
| __WASI_RIGHT_FD_SYNC
43+
| __WASI_RIGHT_FD_ADVISE
44+
| __WASI_RIGHT_FD_FILESTAT_GET
45+
| __WASI_RIGHT_POLL_FD_READWRITE;
46+
const STDOUT_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
47+
| __WASI_RIGHT_FD_WRITE
48+
| __WASI_RIGHT_FD_SYNC
49+
| __WASI_RIGHT_FD_ADVISE
50+
| __WASI_RIGHT_FD_FILESTAT_GET
51+
| __WASI_RIGHT_POLL_FD_READWRITE;
52+
const STDERR_DEFAULT_RIGHTS: __wasi_rights_t = STDOUT_DEFAULT_RIGHTS;
4053

4154
/// Get WasiState from a Ctx
4255
/// This function is unsafe because it must be called on a WASI Ctx
@@ -109,6 +122,7 @@ pub struct Fd {
109122
pub rights_inheriting: __wasi_rights_t,
110123
pub flags: __wasi_fdflags_t,
111124
pub offset: u64,
125+
/// Used when reopening the file on the host system
112126
pub open_flags: u16,
113127
pub inode: Inode,
114128
}
@@ -134,10 +148,6 @@ pub struct WasiFs {
134148
inode_counter: Cell<u64>,
135149
/// for fds still open after the file has been deleted
136150
pub orphan_fds: HashMap<Inode, InodeVal>,
137-
138-
pub stdout: Box<dyn WasiFile>,
139-
pub stderr: Box<dyn WasiFile>,
140-
pub stdin: Box<dyn WasiFile>,
141151
}
142152

143153
impl WasiFs {
@@ -155,11 +165,11 @@ impl WasiFs {
155165
next_fd: Cell::new(3),
156166
inode_counter: Cell::new(1024),
157167
orphan_fds: HashMap::new(),
158-
159-
stdin: Box::new(Stdin),
160-
stdout: Box::new(Stdout),
161-
stderr: Box::new(Stderr),
162168
};
169+
wasi_fs.create_stdin();
170+
wasi_fs.create_stdout();
171+
wasi_fs.create_stderr();
172+
163173
// create virtual root
164174
let root_inode = {
165175
let all_rights = 0x1FFFFFFF;
@@ -291,6 +301,67 @@ impl WasiFs {
291301
Ok(wasi_fs)
292302
}
293303

304+
/// Get the `WasiFile` object at stdout
305+
pub fn stdout(&self) -> Result<&Option<Box<dyn WasiFile>>, WasiFsError> {
306+
self.std_dev_get(__WASI_STDOUT_FILENO)
307+
}
308+
/// Get the `WasiFile` object at stdout mutably
309+
pub fn stdout_mut(&mut self) -> Result<&mut Option<Box<dyn WasiFile>>, WasiFsError> {
310+
self.std_dev_get_mut(__WASI_STDOUT_FILENO)
311+
}
312+
313+
/// Get the `WasiFile` object at stderr
314+
pub fn stderr(&self) -> Result<&Option<Box<dyn WasiFile>>, WasiFsError> {
315+
self.std_dev_get(__WASI_STDERR_FILENO)
316+
}
317+
/// Get the `WasiFile` object at stderr mutably
318+
pub fn stderr_mut(&mut self) -> Result<&mut Option<Box<dyn WasiFile>>, WasiFsError> {
319+
self.std_dev_get_mut(__WASI_STDERR_FILENO)
320+
}
321+
322+
/// Get the `WasiFile` object at stdin
323+
pub fn stdin(&self) -> Result<&Option<Box<dyn WasiFile>>, WasiFsError> {
324+
self.std_dev_get(__WASI_STDIN_FILENO)
325+
}
326+
/// Get the `WasiFile` object at stdin mutably
327+
pub fn stdin_mut(&mut self) -> Result<&mut Option<Box<dyn WasiFile>>, WasiFsError> {
328+
self.std_dev_get_mut(__WASI_STDIN_FILENO)
329+
}
330+
331+
/// Internal helper function to get a standard device handle.
332+
/// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`.
333+
fn std_dev_get(&self, fd: __wasi_fd_t) -> Result<&Option<Box<dyn WasiFile>>, WasiFsError> {
334+
if let Some(fd) = self.fd_map.get(&fd) {
335+
if let Kind::File { ref handle, .. } = self.inodes[fd.inode].kind {
336+
Ok(handle)
337+
} else {
338+
// Our public API should ensure that this is not possible
339+
unreachable!("Non-file found in standard device location")
340+
}
341+
} else {
342+
// this should only trigger if we made a mistake in this crate
343+
Err(WasiFsError::NoDevice)
344+
}
345+
}
346+
/// Internal helper function to mutably get a standard device handle.
347+
/// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`.
348+
fn std_dev_get_mut(
349+
&mut self,
350+
fd: __wasi_fd_t,
351+
) -> Result<&mut Option<Box<dyn WasiFile>>, WasiFsError> {
352+
if let Some(fd) = self.fd_map.get_mut(&fd) {
353+
if let Kind::File { ref mut handle, .. } = self.inodes[fd.inode].kind {
354+
Ok(handle)
355+
} else {
356+
// Our public API should ensure that this is not possible
357+
unreachable!("Non-file found in standard device location")
358+
}
359+
} else {
360+
// this should only trigger if we made a mistake in this crate
361+
Err(WasiFsError::NoDevice)
362+
}
363+
}
364+
294365
fn get_next_inode_index(&mut self) -> u64 {
295366
let next = self.inode_counter.get();
296367
self.inode_counter.set(next + 1);
@@ -358,36 +429,31 @@ impl WasiFs {
358429
fd: __wasi_fd_t,
359430
file: Box<dyn WasiFile>,
360431
) -> Result<Option<Box<dyn WasiFile>>, WasiFsError> {
432+
let mut ret = Some(file);
361433
match fd {
362434
__WASI_STDIN_FILENO => {
363-
let mut ret = file;
364-
std::mem::swap(&mut self.stdin, &mut ret);
365-
Ok(Some(ret))
435+
std::mem::swap(self.stdin_mut()?, &mut ret);
366436
}
367437
__WASI_STDOUT_FILENO => {
368-
let mut ret = file;
369-
std::mem::swap(&mut self.stdout, &mut ret);
370-
Ok(Some(ret))
438+
std::mem::swap(self.stdout_mut()?, &mut ret);
371439
}
372440
__WASI_STDERR_FILENO => {
373-
let mut ret = file;
374-
std::mem::swap(&mut self.stderr, &mut ret);
375-
Ok(Some(ret))
441+
std::mem::swap(self.stderr_mut()?, &mut ret);
376442
}
377443
_ => {
378444
let base_fd = self.get_fd(fd).map_err(WasiFsError::from_wasi_err)?;
379445
let base_inode = base_fd.inode;
380446

381447
match &mut self.inodes[base_inode].kind {
382448
Kind::File { ref mut handle, .. } => {
383-
let mut ret = Some(file);
384449
std::mem::swap(handle, &mut ret);
385-
Ok(ret)
386450
}
387451
_ => return Err(WasiFsError::NotAFile),
388452
}
389453
}
390454
}
455+
456+
Ok(ret)
391457
}
392458

393459
/// refresh size from filesystem
@@ -733,6 +799,17 @@ impl WasiFs {
733799
}
734800

735801
pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> {
802+
match fd {
803+
__WASI_STDOUT_FILENO => {
804+
return Ok(__wasi_fdstat_t {
805+
fs_filetype: __WASI_FILETYPE_CHARACTER_DEVICE,
806+
fs_flags: 0,
807+
fs_rights_base: ALL_RIGHTS,
808+
fs_rights_inheriting: ALL_RIGHTS,
809+
})
810+
}
811+
_ => (),
812+
}
736813
let fd = self.get_fd(fd)?;
737814

738815
debug!("fdstat: {:?}", fd);
@@ -773,8 +850,18 @@ impl WasiFs {
773850
pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> {
774851
match fd {
775852
__WASI_STDIN_FILENO => (),
776-
__WASI_STDOUT_FILENO => self.stdout.flush().map_err(|_| __WASI_EIO)?,
777-
__WASI_STDERR_FILENO => self.stderr.flush().map_err(|_| __WASI_EIO)?,
853+
__WASI_STDOUT_FILENO => self
854+
.stdout_mut()
855+
.map_err(WasiFsError::into_wasi_err)?
856+
.as_mut()
857+
.and_then(|f| f.flush().ok())
858+
.ok_or(__WASI_EIO)?,
859+
__WASI_STDERR_FILENO => self
860+
.stderr_mut()
861+
.map_err(WasiFsError::into_wasi_err)?
862+
.as_mut()
863+
.and_then(|f| f.flush().ok())
864+
.ok_or(__WASI_EIO)?,
778865
_ => {
779866
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
780867
if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 {
@@ -881,13 +968,78 @@ impl WasiFs {
881968
};
882969

883970
self.inodes.insert(InodeVal {
884-
stat: stat,
971+
stat,
885972
is_preopened: true,
886973
name: "/".to_string(),
887974
kind: root_kind,
888975
})
889976
}
890977

978+
fn create_stdout(&mut self) {
979+
self.create_std_dev_inner(
980+
Box::new(Stdout),
981+
"stdout",
982+
__WASI_STDOUT_FILENO,
983+
STDOUT_DEFAULT_RIGHTS,
984+
__WASI_FDFLAG_APPEND,
985+
);
986+
}
987+
fn create_stdin(&mut self) {
988+
self.create_std_dev_inner(
989+
Box::new(Stdin),
990+
"stdin",
991+
__WASI_STDIN_FILENO,
992+
STDIN_DEFAULT_RIGHTS,
993+
0,
994+
);
995+
}
996+
fn create_stderr(&mut self) {
997+
self.create_std_dev_inner(
998+
Box::new(Stderr),
999+
"stderr",
1000+
__WASI_STDERR_FILENO,
1001+
STDERR_DEFAULT_RIGHTS,
1002+
__WASI_FDFLAG_APPEND,
1003+
);
1004+
}
1005+
1006+
fn create_std_dev_inner(
1007+
&mut self,
1008+
handle: Box<dyn WasiFile>,
1009+
name: &'static str,
1010+
raw_fd: __wasi_fd_t,
1011+
rights: __wasi_rights_t,
1012+
fd_flags: __wasi_fdflags_t,
1013+
) {
1014+
let stat = __wasi_filestat_t {
1015+
st_filetype: __WASI_FILETYPE_CHARACTER_DEVICE,
1016+
st_ino: self.get_next_inode_index(),
1017+
..__wasi_filestat_t::default()
1018+
};
1019+
let kind = Kind::File {
1020+
handle: Some(handle),
1021+
path: "".into(),
1022+
};
1023+
let inode = self.inodes.insert(InodeVal {
1024+
stat,
1025+
is_preopened: true,
1026+
name: name.to_string(),
1027+
kind,
1028+
});
1029+
self.fd_map.insert(
1030+
raw_fd,
1031+
Fd {
1032+
rights,
1033+
rights_inheriting: 0,
1034+
flags: fd_flags,
1035+
// since we're not calling open on this, we don't need open flags
1036+
open_flags: 0,
1037+
offset: 0,
1038+
inode,
1039+
},
1040+
);
1041+
}
1042+
8911043
pub fn get_stat_for_kind(&self, kind: &Kind) -> Option<__wasi_filestat_t> {
8921044
let md = match kind {
8931045
Kind::File { handle, path } => match handle {

0 commit comments

Comments
 (0)