Skip to content

Commit

Permalink
implement minimal epoll_create1 shim
Browse files Browse the repository at this point in the history
  • Loading branch information
DebugSteven committed Oct 27, 2022
1 parent dc029cf commit 94d41f0
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::{

// Some global facts about the emulated machine.
pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture
pub const SIGRTMAX: i32 = 42; // should be between 32 and 64
pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever

Expand Down
19 changes: 13 additions & 6 deletions src/shims/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,25 @@ 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;

#[derive(Debug)]
struct FileHandle {
pub struct FileHandle {
file: File,
writable: bool,
}

trait FileDescriptor: std::fmt::Debug {
pub trait FileDescriptor: std::fmt::Debug {
fn name(&self) -> &'static str;

fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
throw_unsup_format!("{} cannot be used as FileHandle", self.name());
}

fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> {
throw_unsup_format!("not an epoll file descriptor");
}

fn read<'tcx>(
&mut self,
_communicate_allowed: bool,
Expand Down Expand Up @@ -275,7 +280,7 @@ impl FileDescriptor for NullOutput {

#[derive(Debug)]
pub struct FileHandler {
handles: BTreeMap<i32, Box<dyn FileDescriptor>>,
pub handles: BTreeMap<i32, Box<dyn FileDescriptor>>,
}

impl VisitTags for FileHandler {
Expand All @@ -298,7 +303,7 @@ impl FileHandler {
FileHandler { handles }
}

fn insert_fd(&mut self, file_handle: Box<dyn FileDescriptor>) -> i32 {
pub fn insert_fd(&mut self, file_handle: Box<dyn FileDescriptor>) -> i32 {
self.insert_fd_with_min_fd(file_handle, 0)
}

Expand Down Expand Up @@ -333,7 +338,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,
Expand Down Expand Up @@ -1908,7 +1915,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<Provenance>,
size: u64,
created: Option<(u64, u32)>,
Expand Down
37 changes: 37 additions & 0 deletions src/shims/unix/linux/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _;
Expand Down Expand Up @@ -42,6 +43,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
this.write_scalar(result, dest)?;
}
"epoll_create1" => {
let [flag] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"epoll_ctl" => {
let [epfd, op, fd, event] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"epoll_wait" => {
let [epfd, events, maxevents, timeout] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.epoll_wait(epfd, events, maxevents, timeout)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"eventfd" => {
let [val, flag] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"socketpair" => {
let [domain, type_, protocol, sv] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

let result = this.socketpair(domain, type_, protocol, sv)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"__libc_current_sigrtmax" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

let result = this.libc_current_sigrtmax()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// Time related shims
"clock_gettime" => {
Expand Down
167 changes: 167 additions & 0 deletions src/shims/unix/linux/fs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use rustc_middle::ty::ScalarInt;

use crate::{machine::SIGRTMAX, *};
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")?;
// FIXME handle cloexec
let _fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?;
if flags == epoll_cloexec {
// FIXME 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")?;

if flags & (efd_cloexec | efd_nonblock | efd_semaphore) == 0 {
throw_unsup_format!("{flags} is unsupported");
}
// FIXME handle the cloexec and nonblock flags
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();

Ok(SIGRTMAX)
}
}
42 changes: 42 additions & 0 deletions src/shims/unix/linux/fs/epoll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::*;

use crate::shims::unix::fs::FileDescriptor;

use rustc_data_structures::fx::FxHashMap;
use std::io;

#[derive(Clone, Debug, Default)]
pub struct Epoll {
pub file_descriptors: FxHashMap<i32, EpollEvent>,
}

#[derive(Clone, Debug)]
pub struct EpollEvent {
pub events: u32,
pub data: u64,
}

impl FileDescriptor for Epoll {
fn name(&self) -> &'static str {
"epoll"
}

fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> {
Ok(self)
}

fn dup<'tcx>(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(self.clone()))
}

fn is_tty(&self) -> bool {
false
}

fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
}
}
39 changes: 39 additions & 0 deletions src/shims/unix/linux/fs/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::shims::unix::fs::FileDescriptor;

use rustc_const_eval::interpret::InterpResult;

use std::io;

#[derive(Debug)]
pub struct Event {
pub val: u32,
}

impl FileDescriptor for Event {
fn name(&self) -> &'static str {
"event"
}

fn dup<'tcx>(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(Event { val: self.val }))
}

fn is_tty(&self) -> bool {
false
}

fn write<'tcx>(
&self,
_communicate_allowed: bool,
bytes: &[u8],
) -> InterpResult<'tcx, io::Result<usize>> {
throw_unsup_format!("cannot write to {}, {:?}", self.name(), bytes);
}

fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
}
}
Loading

0 comments on commit 94d41f0

Please sign in to comment.