Sync with lucet-wasi (#106)

* Open /dev/null for writing as well as reading.

Port this fix to wasi-common:

b905c44483

* Remove all remaining uses of `std::mem::uninitialized`.

Patch inspired by:

2d6519d051

* Replace libc::memcpy() calls with std::ptr::copy_nonoverlapping()

Port this fix to wasi-common:

a3f3a33e9b

* Pass `WasiError` by value.

It's a `u16` underneath, so we can pass it by value.

* Avoid unnecessary explicit lifetime parameters.

* Use immutable references rather than mutable references.

Patch inspired by:

54baa4c38c
This commit is contained in:
Dan Gohman
2019-09-30 10:22:11 -07:00
committed by Jakub Konka
parent d33036a3b5
commit a679412dd0
9 changed files with 46 additions and 29 deletions

View File

@@ -87,8 +87,8 @@ pub enum WasiError {
} }
impl WasiError { impl WasiError {
pub fn as_raw_errno(&self) -> host::__wasi_errno_t { pub fn as_raw_errno(self) -> host::__wasi_errno_t {
*self as host::__wasi_errno_t self as host::__wasi_errno_t
} }
} }

View File

@@ -479,23 +479,23 @@ pub(crate) struct __wasi_subscription_t___wasi_subscription_u___wasi_subscriptio
} }
#[allow(unused)] #[allow(unused)]
pub(crate) unsafe fn ciovec_to_host<'a>(ciovec: &'a __wasi_ciovec_t) -> io::IoSlice<'a> { pub(crate) unsafe fn ciovec_to_host(ciovec: &__wasi_ciovec_t) -> io::IoSlice {
let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len); let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
io::IoSlice::new(slice) io::IoSlice::new(slice)
} }
#[allow(unused)] #[allow(unused)]
pub(crate) unsafe fn ciovec_to_host_mut<'a>(ciovec: &'a mut __wasi_ciovec_t) -> io::IoSliceMut<'a> { pub(crate) unsafe fn ciovec_to_host_mut(ciovec: &mut __wasi_ciovec_t) -> io::IoSliceMut {
let slice = slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len); let slice = slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len);
io::IoSliceMut::new(slice) io::IoSliceMut::new(slice)
} }
pub(crate) unsafe fn iovec_to_host<'a>(iovec: &'a __wasi_iovec_t) -> io::IoSlice<'a> { pub(crate) unsafe fn iovec_to_host(iovec: &__wasi_iovec_t) -> io::IoSlice {
let slice = slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len); let slice = slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len);
io::IoSlice::new(slice) io::IoSlice::new(slice)
} }
pub(crate) unsafe fn iovec_to_host_mut<'a>(iovec: &'a mut __wasi_iovec_t) -> io::IoSliceMut<'a> { pub(crate) unsafe fn iovec_to_host_mut(iovec: &mut __wasi_iovec_t) -> io::IoSliceMut {
let slice = slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len); let slice = slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len);
io::IoSliceMut::new(slice) io::IoSliceMut::new(slice)
} }

View File

@@ -110,7 +110,7 @@ pub(crate) fn enc_slice_of<T>(
// get the pointer into guest memory, and copy the bytes // get the pointer into guest memory, and copy the bytes
let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut libc::c_void; let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut libc::c_void;
unsafe { unsafe {
libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, len_bytes); ptr::copy_nonoverlapping(slice.as_ptr() as *const libc::c_void, ptr, len_bytes);
} }
Ok(()) Ok(())

View File

@@ -62,7 +62,7 @@ pub(crate) fn fd_readdir(
cookie: host::__wasi_dircookie_t, cookie: host::__wasi_dircookie_t,
) -> Result<usize> { ) -> Result<usize> {
use crate::sys::unix::bsd::osfile::DirStream; use crate::sys::unix::bsd::osfile::DirStream;
use libc::{fdopendir, memcpy, readdir, rewinddir, seekdir, telldir}; use libc::{fdopendir, readdir, rewinddir, seekdir, telldir};
use nix::errno::Errno; use nix::errno::Errno;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::sync::Mutex; use std::sync::Mutex;
@@ -129,9 +129,9 @@ pub(crate) fn fd_readdir(
host_buf_offset += std::mem::size_of_val(&entry); host_buf_offset += std::mem::size_of_val(&entry);
let name_ptr = unsafe { *host_entry }.d_name.as_ptr(); let name_ptr = unsafe { *host_entry }.d_name.as_ptr();
unsafe { unsafe {
memcpy( std::ptr::copy_nonoverlapping(
host_buf_ptr.offset(host_buf_offset.try_into()?) as *mut _,
name_ptr as *const _, name_ptr as *const _,
host_buf_ptr.offset(host_buf_offset.try_into()?) as *mut _,
name_len, name_len,
) )
}; };

View File

@@ -5,6 +5,7 @@ use crate::sys::host_impl;
use crate::{host, wasm32, Error, Result}; use crate::{host, wasm32, Error, Result};
use nix::libc::{self, c_int}; use nix::libc::{self, c_int};
use std::cmp; use std::cmp;
use std::mem::MaybeUninit;
use std::time::SystemTime; use std::time::SystemTime;
pub(crate) fn clock_res_get(clock_id: host::__wasi_clockid_t) -> Result<host::__wasi_timestamp_t> { pub(crate) fn clock_res_get(clock_id: host::__wasi_clockid_t) -> Result<host::__wasi_timestamp_t> {
@@ -18,11 +19,12 @@ pub(crate) fn clock_res_get(clock_id: host::__wasi_clockid_t) -> Result<host::__
}; };
// no `nix` wrapper for clock_getres, so we do it ourselves // no `nix` wrapper for clock_getres, so we do it ourselves
let mut timespec = unsafe { std::mem::uninitialized::<libc::timespec>() }; let mut timespec = MaybeUninit::<libc::timespec>::uninit();
let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; let res = unsafe { libc::clock_getres(clock_id, timespec.as_mut_ptr()) };
if res != 0 { if res != 0 {
return Err(host_impl::errno_from_nix(nix::errno::Errno::last())); return Err(host_impl::errno_from_nix(nix::errno::Errno::last()));
} }
let timespec = unsafe { timespec.assume_init() };
// convert to nanoseconds, returning EOVERFLOW in case of overflow; // convert to nanoseconds, returning EOVERFLOW in case of overflow;
// this is freelancing a bit from the spec but seems like it'll // this is freelancing a bit from the spec but seems like it'll
@@ -52,11 +54,12 @@ pub(crate) fn clock_time_get(clock_id: host::__wasi_clockid_t) -> Result<host::_
}; };
// no `nix` wrapper for clock_getres, so we do it ourselves // no `nix` wrapper for clock_getres, so we do it ourselves
let mut timespec = unsafe { std::mem::uninitialized::<libc::timespec>() }; let mut timespec = MaybeUninit::<libc::timespec>::uninit();
let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) };
if res != 0 { if res != 0 {
return Err(host_impl::errno_from_nix(nix::errno::Errno::last())); return Err(host_impl::errno_from_nix(nix::errno::Errno::last()));
} }
let timespec = unsafe { timespec.assume_init() };
// convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
// from the spec but seems like it'll be an unusual situation to hit // from the spec but seems like it'll be an unusual situation to hit

View File

@@ -6,6 +6,7 @@ use nix::libc::{self, c_long, c_void};
use std::convert::TryInto; use std::convert::TryInto;
use std::ffi::CString; use std::ffi::CString;
use std::fs::File; use std::fs::File;
use std::mem::MaybeUninit;
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
@@ -33,7 +34,7 @@ pub(crate) fn fd_readdir(
host_buf: &mut [u8], host_buf: &mut [u8],
cookie: host::__wasi_dircookie_t, cookie: host::__wasi_dircookie_t,
) -> Result<usize> { ) -> Result<usize> {
use libc::{dirent, fdopendir, memcpy, readdir_r, rewinddir, seekdir}; use libc::{dirent, fdopendir, readdir_r, rewinddir, seekdir};
let host_buf_ptr = host_buf.as_mut_ptr(); let host_buf_ptr = host_buf.as_mut_ptr();
let host_buf_len = host_buf.len(); let host_buf_len = host_buf.len();
@@ -50,7 +51,7 @@ pub(crate) fn fd_readdir(
unsafe { rewinddir(dir) }; unsafe { rewinddir(dir) };
} }
let mut entry_buf = unsafe { std::mem::uninitialized::<dirent>() }; let mut entry_buf = MaybeUninit::<dirent>::uninit();
let mut left = host_buf_len; let mut left = host_buf_len;
let mut host_buf_offset: usize = 0; let mut host_buf_offset: usize = 0;
while left > 0 { while left > 0 {
@@ -61,13 +62,14 @@ pub(crate) fn fd_readdir(
// replacing it with `readdir` call instead. // replacing it with `readdir` call instead.
// Also, `readdir_r` returns a positive int on failure, and doesn't // Also, `readdir_r` returns a positive int on failure, and doesn't
// set the errno. // set the errno.
let res = unsafe { readdir_r(dir, &mut entry_buf, &mut host_entry) }; let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) };
if res == -1 { if res == -1 {
return Err(host_impl::errno_from_nix(nix::errno::Errno::last())); return Err(host_impl::errno_from_nix(nix::errno::Errno::last()));
} }
if host_entry.is_null() { if host_entry.is_null() {
break; break;
} }
unsafe { entry_buf.assume_init() };
let entry: host::__wasi_dirent_t = host_impl::dirent_from_host(&unsafe { *host_entry })?; let entry: host::__wasi_dirent_t = host_impl::dirent_from_host(&unsafe { *host_entry })?;
log::debug!("fd_readdir entry = {:?}", entry); log::debug!("fd_readdir entry = {:?}", entry);
@@ -85,9 +87,9 @@ pub(crate) fn fd_readdir(
host_buf_offset += std::mem::size_of_val(&entry); host_buf_offset += std::mem::size_of_val(&entry);
let name_ptr = unsafe { *host_entry }.d_name.as_ptr(); let name_ptr = unsafe { *host_entry }.d_name.as_ptr();
unsafe { unsafe {
memcpy( std::ptr::copy_nonoverlapping(
host_buf_ptr.offset(host_buf_offset.try_into()?) as *mut _,
name_ptr as *const _, name_ptr as *const _,
host_buf_ptr.offset(host_buf_offset.try_into()?) as *mut _,
name_len, name_len,
) )
}; };

View File

@@ -15,11 +15,15 @@ mod bsd;
mod linux; mod linux;
use crate::Result; use crate::Result;
use std::fs::File; use std::fs::{File, OpenOptions};
use std::path::Path; use std::path::Path;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
File::open("/dev/null").map_err(Into::into) OpenOptions::new()
.read(true)
.write(true)
.open("/dev/null")
.map_err(Into::into)
} }
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> { pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {

View File

@@ -3,11 +3,15 @@ pub(crate) mod host_impl;
pub(crate) mod hostcalls_impl; pub(crate) mod hostcalls_impl;
use crate::Result; use crate::Result;
use std::fs::File; use std::fs::{File, OpenOptions};
use std::path::Path; use std::path::Path;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
File::open("NUL").map_err(Into::into) OpenOptions::new()
.read(true)
.write(true)
.open("NUL")
.map_err(Into::into)
} }
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> { pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {

View File

@@ -62,12 +62,16 @@ pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenSt
arg_ident.push(quote!(#len_ident)); arg_ident.push(quote!(#len_ident));
arg_type.push(quote!(usize)); arg_type.push(quote!(usize));
} else { } else {
// & or &mut type // & or &mut type; substitute with *const or *mut type.
// so simply substitute with *mut type // Also, we need to properly dereference the substituted raw
arg_type.push(quote!(*mut #elem)); // pointer if we are to properly call the hostcall fn.
// we need to properly dereference the substituted raw if ty.mutability.is_none() {
// pointer if we are to properly call the hostcall fn arg_type.push(quote!(*const #elem));
call_arg_ident.push(quote!(&mut *#ident)); call_arg_ident.push(quote!(&*#ident));
} else {
arg_type.push(quote!(*mut #elem));
call_arg_ident.push(quote!(&mut *#ident));
}
} }
} else { } else {
arg_type.push(quote!(#ty)); arg_type.push(quote!(#ty));