Browse Source

Misc yanix fixes (#715)

* Correctly handle possibly misaligned pointers in readdir

This reapplies #615, which was inadvertently reverted.

* Tidy up unneeded `self::` qualifiers.

* Make Dir's contents private.

Also remove the `unsafe` from `impl_iter`. With `Dir`'s field being
private, we can rely on the pointer being only what we've assigned to
it.

* Make `poll`'s timeout argument a `libc::c_int`.

This clarifies that there are no subsequent conversions before calling the
underlying libc API.

* Use clock_gettime instead of clock_getres to get the time.

* Mark FileType::from_raw as safe.

It handles unknown values, so it can be marked safe.
pull/730/head
Dan Gohman 5 years ago
committed by GitHub
parent
commit
c2ba419409
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      crates/wasi-common/src/host.rs
  2. 4
      crates/wasi-common/src/old/snapshot_0/host.rs
  3. 4
      crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs
  4. 8
      crates/wasi-common/src/sys/mod.rs
  5. 4
      crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs
  6. 8
      crates/wasi-common/yanix/src/clock.rs
  7. 14
      crates/wasi-common/yanix/src/dir.rs
  8. 2
      crates/wasi-common/yanix/src/poll.rs
  9. 6
      crates/wasi-common/yanix/src/sys/bsd/dir.rs
  10. 6
      crates/wasi-common/yanix/src/sys/linux/dir.rs
  11. 6
      crates/wasi-common/yanix/src/sys/mod.rs

4
crates/wasi-common/src/host.rs

@ -63,12 +63,12 @@ impl Dirent {
let sys_dirent = raw.as_mut_ptr() as *mut __wasi_dirent_t; let sys_dirent = raw.as_mut_ptr() as *mut __wasi_dirent_t;
unsafe { unsafe {
*sys_dirent = __wasi_dirent_t { sys_dirent.write_unaligned(__wasi_dirent_t {
d_namlen: namlen.try_into()?, d_namlen: namlen.try_into()?,
d_ino: self.ino, d_ino: self.ino,
d_next: self.cookie, d_next: self.cookie,
d_type: self.ftype.to_wasi(), d_type: self.ftype.to_wasi(),
}; });
} }
let sys_name = unsafe { sys_dirent.offset(1) as *mut u8 }; let sys_name = unsafe { sys_dirent.offset(1) as *mut u8 };

4
crates/wasi-common/src/old/snapshot_0/host.rs

@ -63,12 +63,12 @@ impl Dirent {
let sys_dirent = raw.as_mut_ptr() as *mut __wasi_dirent_t; let sys_dirent = raw.as_mut_ptr() as *mut __wasi_dirent_t;
unsafe { unsafe {
*sys_dirent = __wasi_dirent_t { sys_dirent.write_unaligned(__wasi_dirent_t {
d_namlen: namlen.try_into()?, d_namlen: namlen.try_into()?,
d_ino: self.ino, d_ino: self.ino,
d_next: self.cookie, d_next: self.cookie,
d_type: self.ftype.to_wasi(), d_type: self.ftype.to_wasi(),
}; });
} }
let sys_name = unsafe { sys_dirent.offset(1) as *mut u8 }; let sys_name = unsafe { sys_dirent.offset(1) as *mut u8 };

4
crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs

@ -3,7 +3,7 @@
use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData}; use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData};
use crate::old::snapshot_0::sys::host_impl; use crate::old::snapshot_0::sys::host_impl;
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::{wasi, Error, Result};
use yanix::clock::{clock_getres, ClockId}; use yanix::clock::{clock_getres, clock_gettime, ClockId};
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> { fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> {
// convert the supported clocks to libc types, or return EINVAL // convert the supported clocks to libc types, or return EINVAL
@ -39,7 +39,7 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_getres(clock_id)?; let timespec = clock_gettime(clock_id)?;
// 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

8
crates/wasi-common/src/sys/mod.rs

@ -4,16 +4,16 @@ use cfg_if::cfg_if;
cfg_if! { cfg_if! {
if #[cfg(unix)] { if #[cfg(unix)] {
mod unix; mod unix;
pub(crate) use self::unix::*; pub(crate) use unix::*;
pub use self::unix::preopen_dir; pub use unix::preopen_dir;
pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t { pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t {
host_impl::errno_from_nix(yanix::Errno::from_i32(err)).as_wasi_errno() host_impl::errno_from_nix(yanix::Errno::from_i32(err)).as_wasi_errno()
} }
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
mod windows; mod windows;
pub(crate) use self::windows::*; pub(crate) use windows::*;
pub use self::windows::preopen_dir; pub use windows::preopen_dir;
pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t { pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t {
host_impl::errno_from_win(winx::winerror::WinError::from_u32(err as u32)) host_impl::errno_from_win(winx::winerror::WinError::from_u32(err as u32))

4
crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs

@ -3,7 +3,7 @@
use crate::hostcalls_impl::{ClockEventData, FdEventData}; use crate::hostcalls_impl::{ClockEventData, FdEventData};
use crate::sys::host_impl; use crate::sys::host_impl;
use crate::{wasi, Error, Result}; use crate::{wasi, Error, Result};
use yanix::clock::{clock_getres, ClockId}; use yanix::clock::{clock_getres, clock_gettime, ClockId};
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> { fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> {
// convert the supported clocks to libc types, or return EINVAL // convert the supported clocks to libc types, or return EINVAL
@ -39,7 +39,7 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_getres(clock_id)?; let timespec = clock_gettime(clock_id)?;
// 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

8
crates/wasi-common/yanix/src/clock.rs

@ -27,3 +27,11 @@ pub fn clock_getres(clock_id: ClockId) -> Result<libc::timespec> {
})?; })?;
Ok(unsafe { timespec.assume_init() }) Ok(unsafe { timespec.assume_init() })
} }
pub fn clock_gettime(clock_id: ClockId) -> Result<libc::timespec> {
let mut timespec = MaybeUninit::<libc::timespec>::uninit();
Errno::from_success_code(unsafe {
libc::clock_gettime(clock_id.as_raw(), timespec.as_mut_ptr())
})?;
Ok(unsafe { timespec.assume_init() })
}

14
crates/wasi-common/yanix/src/dir.rs

@ -8,7 +8,7 @@ use std::{ffi::CStr, ops::Deref, ptr};
pub use crate::sys::EntryExt; pub use crate::sys::EntryExt;
#[derive(Clone, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Dir(pub(crate) ptr::NonNull<libc::DIR>); pub struct Dir(ptr::NonNull<libc::DIR>);
impl Dir { impl Dir {
/// Takes the ownership of the passed-in descriptor-based object, /// Takes the ownership of the passed-in descriptor-based object,
@ -51,6 +51,12 @@ impl Dir {
let loc = unsafe { libc::telldir(self.0.as_ptr()) }; let loc = unsafe { libc::telldir(self.0.as_ptr()) };
SeekLoc(loc) SeekLoc(loc)
} }
/// For use by platform-specific implementation code. Returns the raw
/// underlying state.
pub(crate) fn as_raw(&self) -> ptr::NonNull<libc::DIR> {
self.0
}
} }
unsafe impl Send for Dir {} unsafe impl Send for Dir {}
@ -78,7 +84,7 @@ impl Entry {
/// Returns the type of this directory entry. /// Returns the type of this directory entry.
pub fn file_type(&self) -> FileType { pub fn file_type(&self) -> FileType {
unsafe { FileType::from_raw(self.0.d_type) } FileType::from_raw(self.0.d_type)
} }
} }
@ -107,7 +113,7 @@ pub enum FileType {
} }
impl FileType { impl FileType {
pub unsafe fn from_raw(file_type: u8) -> Self { pub fn from_raw(file_type: u8) -> Self {
match file_type { match file_type {
libc::DT_CHR => Self::CharacterDevice, libc::DT_CHR => Self::CharacterDevice,
libc::DT_DIR => Self::Directory, libc::DT_DIR => Self::Directory,
@ -153,6 +159,6 @@ where
type Item = Result<Entry>; type Item = Result<Entry>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
unsafe { iter_impl(&self.0).map(|x| x.map(Entry)) } iter_impl(&self.0).map(|x| x.map(Entry))
} }
} }

2
crates/wasi-common/yanix/src/poll.rs

@ -35,7 +35,7 @@ impl PollFd {
} }
} }
pub fn poll(fds: &mut [PollFd], timeout: i32) -> Result<usize> { pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<usize> {
Errno::from_result(unsafe { Errno::from_result(unsafe {
libc::poll( libc::poll(
fds.as_mut_ptr() as *mut libc::pollfd, fds.as_mut_ptr() as *mut libc::pollfd,

6
crates/wasi-common/yanix/src/sys/bsd/dir.rs

@ -18,9 +18,9 @@ impl Deref for EntryImpl {
} }
} }
pub(crate) unsafe fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> { pub(crate) fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> {
let errno = Errno::last(); let errno = Errno::last();
let dirent = libc::readdir(dir.0.as_ptr()); let dirent = unsafe { libc::readdir(dir.as_raw().as_ptr()) };
if dirent.is_null() { if dirent.is_null() {
if errno != Errno::last() { if errno != Errno::last() {
// TODO This should be verified on different BSD-flavours. // TODO This should be verified on different BSD-flavours.
@ -35,7 +35,7 @@ pub(crate) unsafe fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> {
} }
} else { } else {
Some(Ok(EntryImpl { Some(Ok(EntryImpl {
dirent: *dirent, dirent: unsafe { *dirent },
loc: dir.tell(), loc: dir.tell(),
})) }))
} }

6
crates/wasi-common/yanix/src/sys/linux/dir.rs

@ -25,9 +25,9 @@ impl EntryExt for Entry {
} }
} }
pub(crate) unsafe fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> { pub(crate) fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> {
let errno = Errno::last(); let errno = Errno::last();
let dirent = libc::readdir64(dir.0.as_ptr()); let dirent = unsafe { libc::readdir64(dir.as_raw().as_ptr()) };
if dirent.is_null() { if dirent.is_null() {
if errno != Errno::last() { if errno != Errno::last() {
// TODO This should be verified on different BSD-flavours. // TODO This should be verified on different BSD-flavours.
@ -41,6 +41,6 @@ pub(crate) unsafe fn iter_impl(dir: &Dir) -> Option<Result<EntryImpl>> {
None None
} }
} else { } else {
Some(Ok(EntryImpl(*dirent))) Some(Ok(EntryImpl(unsafe { *dirent })))
} }
} }

6
crates/wasi-common/yanix/src/sys/mod.rs

@ -5,10 +5,10 @@ cfg_if! {
if #[cfg(any(target_os = "linux", if #[cfg(any(target_os = "linux",
target_os = "android"))] { target_os = "android"))] {
mod linux; mod linux;
pub(crate) use self::linux::*; pub(crate) use linux::*;
} else if #[cfg(target_os = "emscripten")] { } else if #[cfg(target_os = "emscripten")] {
mod emscripten; mod emscripten;
pub(crate) use self::emscripten::*; pub(crate) use emscripten::*;
} else if #[cfg(any(target_os = "macos", } else if #[cfg(any(target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "freebsd", target_os = "freebsd",
@ -16,7 +16,7 @@ cfg_if! {
target_os = "openbsd", target_os = "openbsd",
target_os = "dragonfly"))] { target_os = "dragonfly"))] {
mod bsd; mod bsd;
pub(crate) use self::bsd::*; pub(crate) use bsd::*;
} else { } else {
compile_error!("yanix doesn't compile for this platform yet"); compile_error!("yanix doesn't compile for this platform yet");
} }

Loading…
Cancel
Save