Browse Source

wasi-common: don't rely on platform dependent "NUL" device

If stdio is not inherited nor associated with a file, WasiCtxBuilder
tries to open "/dev/null" ("NUL" on Windows) and attach stdio to it.
While most platforms today support those device files, it would be
good to avoid unnecessary access to the host device if possible.  This
patch instead uses a virtual Handle that emulates the "NUL" device.
pull/1855/head
Daiki Ueno 4 years ago
parent
commit
65ebfc3a03
  1. 8
      crates/wasi-common/src/ctx.rs
  2. 2
      crates/wasi-common/src/lib.rs
  3. 7
      crates/wasi-common/src/sys/osother.rs
  4. 59
      crates/wasi-common/src/sys/stdio.rs
  5. 16
      crates/wasi-common/src/sys/unix/osother.rs
  6. 13
      crates/wasi-common/src/sys/windows/osother.rs

8
crates/wasi-common/src/ctx.rs

@ -2,7 +2,7 @@ use crate::entry::{Entry, EntryHandle};
use crate::fdpool::FdPool;
use crate::handle::Handle;
use crate::sys::osdir::OsDir;
use crate::sys::osother::{OsOther, OsOtherExt};
use crate::sys::stdio::NullDevice;
use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt};
use crate::virtfs::{VirtualDir, VirtualDirEntry};
use crate::wasi::types;
@ -136,9 +136,9 @@ pub struct WasiCtxBuilder {
impl WasiCtxBuilder {
/// Builder for a new `WasiCtx`.
pub fn new() -> Self {
let stdin = Some(PendingEntry::Thunk(OsOther::from_null));
let stdout = Some(PendingEntry::Thunk(OsOther::from_null));
let stderr = Some(PendingEntry::Thunk(OsOther::from_null));
let stdin = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
let stdout = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
let stderr = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
Self {
stdin,

2
crates/wasi-common/src/lib.rs

@ -39,6 +39,6 @@ pub use ctx::{WasiCtx, WasiCtxBuilder, WasiCtxBuilderError};
pub use handle::{Handle, HandleRights};
pub use sys::osdir::OsDir;
pub use sys::osfile::OsFile;
pub use sys::osother::{OsOther, OsOtherExt};
pub use sys::osother::OsOther;
pub use sys::preopen_dir;
pub use virtfs::{FileContents, VirtualDirEntry};

7
crates/wasi-common/src/sys/osother.rs

@ -10,13 +10,6 @@ use std::fs::File;
use std::io::{self, Read, Write};
use std::ops::Deref;
/// Extra methods for `OsOther` that are only available when configured for
/// some operating systems.
pub trait OsOtherExt {
/// Create `OsOther` as `dyn Handle` from null device.
fn from_null() -> io::Result<Box<dyn Handle>>;
}
/// `OsOther` is something of a catch-all for everything not covered with the specific handle
/// types (`OsFile`, `OsDir`, `Stdio`). It currently encapsulates handles such as OS pipes,
/// sockets, streams, etc. As such, when redirecting stdio within `WasiCtxBuilder`, the redirected

59
crates/wasi-common/src/sys/stdio.rs

@ -20,9 +20,10 @@ use super::{fd, AsFile};
use crate::handle::{Handle, HandleRights};
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use crate::wasi::types::{self, Filetype};
use crate::wasi::Result;
use crate::wasi::{Errno, Result, RightsExt};
use std::any::Any;
use std::cell::Cell;
use std::convert::TryInto;
use std::io::{self, Read, Write};
pub(crate) trait StdinExt: Sized {
@ -174,3 +175,59 @@ impl Handle for Stderr {
Ok(nwritten)
}
}
#[derive(Debug, Clone)]
pub(crate) struct NullDevice {
pub(crate) rights: Cell<HandleRights>,
pub(crate) fd_flags: Cell<types::Fdflags>,
}
impl NullDevice {
pub(crate) fn new() -> Self {
let rights = HandleRights::new(
types::Rights::character_device_base(),
types::Rights::character_device_inheriting(),
);
let rights = Cell::new(rights);
let fd_flags = types::Fdflags::empty();
let fd_flags = Cell::new(fd_flags);
Self { rights, fd_flags }
}
}
impl Handle for NullDevice {
fn as_any(&self) -> &dyn Any {
self
}
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
Ok(Box::new(self.clone()))
}
fn get_file_type(&self) -> types::Filetype {
types::Filetype::CharacterDevice
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, rights: HandleRights) {
self.rights.set(rights)
}
// FdOps
fn fdstat_get(&self) -> Result<types::Fdflags> {
Ok(self.fd_flags.get())
}
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
self.fd_flags.set(fdflags);
Ok(())
}
fn read_vectored(&self, _iovs: &mut [io::IoSliceMut]) -> Result<usize> {
Ok(0)
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let mut total_len = 0u32;
for iov in iovs {
let len: types::Size = iov.len().try_into()?;
total_len = total_len.checked_add(len).ok_or(Errno::Overflow)?;
}
Ok(total_len as usize)
}
}

16
crates/wasi-common/src/sys/unix/osother.rs

@ -1,10 +1,9 @@
use super::oshandle::RawOsHandle;
use super::{get_file_type, get_rights};
use crate::handle::Handle;
use crate::sys::osother::{OsOther, OsOtherExt};
use crate::sys::osother::OsOther;
use crate::wasi::types;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::fs::File;
use std::io;
use std::os::unix::prelude::{FromRawFd, IntoRawFd};
@ -21,14 +20,3 @@ impl TryFrom<File> for OsOther {
Ok(Self::new(file_type, rights, handle))
}
}
impl OsOtherExt for OsOther {
fn from_null() -> io::Result<Box<dyn Handle>> {
let file = OpenOptions::new()
.read(true)
.write(true)
.open("/dev/null")?;
let file = Self::try_from(file)?;
Ok(Box::new(file))
}
}

13
crates/wasi-common/src/sys/windows/osother.rs

@ -1,10 +1,9 @@
use super::oshandle::RawOsHandle;
use super::{get_file_type, get_rights};
use crate::handle::Handle;
use crate::sys::osother::{OsOther, OsOtherExt};
use crate::sys::osother::OsOther;
use crate::wasi::types;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::fs::File;
use std::io;
use std::os::windows::prelude::{FromRawHandle, IntoRawHandle};
@ -21,11 +20,3 @@ impl TryFrom<File> for OsOther {
Ok(Self::new(file_type, rights, handle))
}
}
impl OsOtherExt for OsOther {
fn from_null() -> io::Result<Box<dyn Handle>> {
let file = OpenOptions::new().read(true).write(true).open("NUL")?;
let file = Self::try_from(file)?;
Ok(Box::new(file))
}
}

Loading…
Cancel
Save