diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index a1de23c152..3c795ae987 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -11,16 +11,14 @@ use std::time::SystemTime; use log::trace; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::{self, layout::LayoutOf, ScalarInt}; +use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; use crate::shims::os_str::bytes_to_os_str; use crate::*; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; -use shims::unix::linux::fs::epoll::{Epoll, EpollEvent}; -use shims::unix::linux::fs::event::Event; -use shims::unix::linux::fs::socketpair::SocketPair; +use shims::unix::linux::fs::epoll::Epoll; #[derive(Debug)] pub struct FileHandle { @@ -260,7 +258,7 @@ impl FileDescriptor for DummyOutput { #[derive(Debug)] pub struct FileHandler { - handles: BTreeMap>, + pub handles: BTreeMap>, } impl VisitTags for FileHandler { @@ -283,7 +281,7 @@ impl FileHandler { FileHandler { handles } } - fn insert_fd(&mut self, file_handle: Box) -> i32 { + pub fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } @@ -318,7 +316,9 @@ impl FileHandler { } impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { +pub(super) trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ fn macos_stat_write_buf( &mut self, metadata: FileMetadata, @@ -703,155 +703,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { )) } - fn epoll_create1(&mut self, flags: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let flags = this.read_scalar(flags)?.to_i32()?; - - let epoll_cloexec = this.eval_libc_i32("EPOLL_CLOEXEC")?; - // TODO actually do the thing - let _fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if flags == epoll_cloexec { - // set close on exec, FD_CLOEXEC - } else if flags != 0 { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - return Ok(-1); - } - - let fh = &mut this.machine.file_handler; - #[allow(clippy::box_default)] - let fd = fh.insert_fd(Box::new(Epoll::default())); - Ok(fd) - } - - fn epoll_ctl( - &mut self, - epfd: &OpTy<'tcx, Provenance>, - op: &OpTy<'tcx, Provenance>, - fd: &OpTy<'tcx, Provenance>, - event: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let values = this.read_scalar(op)?.to_i32()?; - let epfd = this.read_scalar(epfd)?.to_i32()?; - let fd = this.read_scalar(fd)?.to_i32()?; - - let epoll_ctl_add = this.eval_libc_i32("EPOLL_CTL_ADD")?; - let epoll_ctl_mod = this.eval_libc_i32("EPOLL_CTL_MOD")?; - let epoll_ctl_del = this.eval_libc_i32("EPOLL_CTL_DEL")?; - - if values == epoll_ctl_add || values == epoll_ctl_mod { - let event = this.deref_operand(event)?; - - let events = this.mplace_field(&event, 0)?; - let events = this.read_scalar(&events.into())?.to_u32()?; - let data = this.mplace_field(&event, 1)?; - let data = this.read_scalar(&data.into())?.to_u64()?; - let event = EpollEvent { events, data }; - - if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; - - epfd.file_descriptors.insert(fd, event); - Ok(0) - } else { - this.handle_not_found() - } - } else if values == epoll_ctl_del { - if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; - - epfd.file_descriptors.remove(&fd); - Ok(0) - } else { - this.handle_not_found() - } - } else { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } - } - - fn epoll_wait( - &mut self, - epfd: &OpTy<'tcx, Provenance>, - events: &OpTy<'tcx, Provenance>, - maxevents: &OpTy<'tcx, Provenance>, - timeout: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let _epfd = this.read_scalar(epfd)?.to_i32()?; - let _events = this.read_scalar(events)?; - let maxevents = this.read_scalar(maxevents)?.to_i32()?; - let _timeout = this.read_scalar(timeout)?.to_i32()?; - - if maxevents <= 0 { - throw_ub_format!("maxevents must be greater than 0"); - } - - throw_ub_format!("closed due to not writing"); - } - - fn eventfd( - &mut self, - val: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let val = this.read_scalar(val)?.to_u32()?; - let flags = this.read_scalar(flags)?.to_i32()?; - - let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC")?; - let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK")?; - let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE")?; - // TODO actually do the thing - if flags & efd_cloexec != 0 {} - if flags & efd_nonblock != 0 {} - if flags & efd_semaphore != 0 { - throw_unsup_format!("EFD_SEMAPHORE is unsupported"); - } - - let fh = &mut this.machine.file_handler; - let fd = fh.insert_fd(Box::new(Event { val })); - Ok(fd) - } - - fn socketpair( - &mut self, - _domain: &OpTy<'tcx, Provenance>, - type_: &OpTy<'tcx, Provenance>, - _protocol: &OpTy<'tcx, Provenance>, - sv: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let _flags = this.read_scalar(type_)?.to_i32()?; - let sv = this.deref_operand(sv)?; - - let fh = &mut this.machine.file_handler; - let sv0 = fh.insert_fd(Box::new(SocketPair)); - let sv0 = ScalarInt::try_from_int(sv0, sv.layout.size).unwrap(); - let sv1 = fh.insert_fd(Box::new(SocketPair)); - let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap(); - - this.write_scalar(sv0, &sv.into())?; - this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?.into())?; - - Ok(0) - } - - fn libc_current_sigrtmax(&mut self) -> InterpResult<'tcx, i32> { - let _this = self.eval_context_mut(); - - // TODO return the correct value - Ok(42) - } - fn read( &mut self, fd: i32, @@ -2054,7 +1905,7 @@ fn extract_sec_and_nsec<'tcx>( /// Stores a file's metadata in order to avoid code duplication in the different metadata related /// shims. -struct FileMetadata { +pub(super) struct FileMetadata { mode: Scalar, size: u64, created: Option<(u64, u32)>, diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 990a6e93a1..a84637a1e6 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -4,6 +4,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::unix::fs::EvalContextExt as _; +use shims::unix::linux::fs::EvalContextExt as _; use shims::unix::linux::sync::futex; use shims::unix::sync::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; diff --git a/src/shims/unix/linux/fs.rs b/src/shims/unix/linux/fs.rs index 15bfd17456..9e98819bee 100644 --- a/src/shims/unix/linux/fs.rs +++ b/src/shims/unix/linux/fs.rs @@ -1,3 +1,164 @@ +use rustc_middle::ty::ScalarInt; + +use crate::*; +use epoll::{Epoll, EpollEvent}; +use event::Event; +use socketpair::SocketPair; + +use shims::unix::fs::EvalContextExtPrivate; + pub mod epoll; pub mod event; pub mod socketpair; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + fn epoll_create1(&mut self, flags: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let flags = this.read_scalar(flags)?.to_i32()?; + + let epoll_cloexec = this.eval_libc_i32("EPOLL_CLOEXEC")?; + // TODO actually do the thing + let _fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; + if flags == epoll_cloexec { + // set close on exec, FD_CLOEXEC + } else if flags != 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + let fh = &mut this.machine.file_handler; + #[allow(clippy::box_default)] + let fd = fh.insert_fd(Box::new(Epoll::default())); + Ok(fd) + } + + fn epoll_ctl( + &mut self, + epfd: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx, Provenance>, + fd: &OpTy<'tcx, Provenance>, + event: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let values = this.read_scalar(op)?.to_i32()?; + let epfd = this.read_scalar(epfd)?.to_i32()?; + let fd = this.read_scalar(fd)?.to_i32()?; + + let epoll_ctl_add = this.eval_libc_i32("EPOLL_CTL_ADD")?; + let epoll_ctl_mod = this.eval_libc_i32("EPOLL_CTL_MOD")?; + let epoll_ctl_del = this.eval_libc_i32("EPOLL_CTL_DEL")?; + + if values == epoll_ctl_add || values == epoll_ctl_mod { + let event = this.deref_operand(event)?; + + let events = this.mplace_field(&event, 0)?; + let events = this.read_scalar(&events.into())?.to_u32()?; + let data = this.mplace_field(&event, 1)?; + let data = this.read_scalar(&data.into())?.to_u64()?; + let event = EpollEvent { events, data }; + + if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { + let epfd = epfd.as_epoll_handle()?; + + epfd.file_descriptors.insert(fd, event); + Ok(0) + } else { + this.handle_not_found() + } + } else if values == epoll_ctl_del { + if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { + let epfd = epfd.as_epoll_handle()?; + + epfd.file_descriptors.remove(&fd); + Ok(0) + } else { + this.handle_not_found() + } + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } + + fn epoll_wait( + &mut self, + epfd: &OpTy<'tcx, Provenance>, + events: &OpTy<'tcx, Provenance>, + maxevents: &OpTy<'tcx, Provenance>, + timeout: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let _epfd = this.read_scalar(epfd)?.to_i32()?; + let _events = this.read_scalar(events)?; + let maxevents = this.read_scalar(maxevents)?.to_i32()?; + let _timeout = this.read_scalar(timeout)?.to_i32()?; + + if maxevents <= 0 { + throw_ub_format!("maxevents must be greater than 0"); + } + + throw_ub_format!("closed due to not writing"); + } + + fn eventfd( + &mut self, + val: &OpTy<'tcx, Provenance>, + flags: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let val = this.read_scalar(val)?.to_u32()?; + let flags = this.read_scalar(flags)?.to_i32()?; + + let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC")?; + let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK")?; + let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE")?; + // TODO actually do the thing + if flags & efd_cloexec != 0 {} + if flags & efd_nonblock != 0 {} + if flags & efd_semaphore != 0 { + throw_unsup_format!("EFD_SEMAPHORE is unsupported"); + } + + let fh = &mut this.machine.file_handler; + let fd = fh.insert_fd(Box::new(Event { val })); + Ok(fd) + } + + fn socketpair( + &mut self, + _domain: &OpTy<'tcx, Provenance>, + type_: &OpTy<'tcx, Provenance>, + _protocol: &OpTy<'tcx, Provenance>, + sv: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let _flags = this.read_scalar(type_)?.to_i32()?; + let sv = this.deref_operand(sv)?; + + let fh = &mut this.machine.file_handler; + let sv0 = fh.insert_fd(Box::new(SocketPair)); + let sv0 = ScalarInt::try_from_int(sv0, sv.layout.size).unwrap(); + let sv1 = fh.insert_fd(Box::new(SocketPair)); + let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap(); + + this.write_scalar(sv0, &sv.into())?; + this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?.into())?; + + Ok(0) + } + + fn libc_current_sigrtmax(&mut self) -> InterpResult<'tcx, i32> { + let _this = self.eval_context_mut(); + + // TODO return the correct value + Ok(42) + } +}