Make file descriptors into refcount references

take ownership of self and return `io::Result<()>` in `FileDescription::close`

Co-authored-by: Ralf Jung <post@ralfj.de>
This commit is contained in:
Luv-Ray 2024-05-04 17:24:18 +08:00
parent ca3defe245
commit 459c6ce944
6 changed files with 192 additions and 200 deletions

View File

@ -2,8 +2,10 @@
//! standard file descriptors (stdin/stdout/stderr).
use std::any::Any;
use std::cell::{Ref, RefCell, RefMut};
use std::collections::BTreeMap;
use std::io::{self, ErrorKind, IsTerminal, Read, SeekFrom, Write};
use std::rc::Rc;
use rustc_middle::ty::TyCtxt;
use rustc_target::abi::Size;
@ -12,7 +14,7 @@
use crate::*;
/// Represents an open file descriptor.
pub trait FileDescriptor: std::fmt::Debug + Any {
pub trait FileDescription: std::fmt::Debug + Any {
fn name(&self) -> &'static str;
fn read<'tcx>(
@ -44,13 +46,10 @@ fn seek<'tcx>(
fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
) -> InterpResult<'tcx, io::Result<()>> {
throw_unsup_format!("cannot close {}", self.name());
}
/// Return a new file descriptor *that refers to the same underlying object*.
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>;
fn is_tty(&self, _communicate_allowed: bool) -> bool {
// Most FDs are not tty's and the consequence of a wrong `false` are minor,
// so we use a default impl here.
@ -58,7 +57,7 @@ fn is_tty(&self, _communicate_allowed: bool) -> bool {
}
}
impl dyn FileDescriptor {
impl dyn FileDescription {
#[inline(always)]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref()
@ -70,7 +69,7 @@ pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
}
}
impl FileDescriptor for io::Stdin {
impl FileDescription for io::Stdin {
fn name(&self) -> &'static str {
"stdin"
}
@ -88,16 +87,12 @@ fn read<'tcx>(
Ok(Read::read(self, bytes))
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(io::stdin()))
}
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
}
impl FileDescriptor for io::Stdout {
impl FileDescription for io::Stdout {
fn name(&self) -> &'static str {
"stdout"
}
@ -120,16 +115,12 @@ fn write<'tcx>(
Ok(result)
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(io::stdout()))
}
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
}
impl FileDescriptor for io::Stderr {
impl FileDescription for io::Stderr {
fn name(&self) -> &'static str {
"stderr"
}
@ -145,10 +136,6 @@ fn write<'tcx>(
Ok(Write::write(&mut { self }, bytes))
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(io::stderr()))
}
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.is_terminal()
}
@ -158,7 +145,7 @@ fn is_tty(&self, communicate_allowed: bool) -> bool {
#[derive(Debug)]
pub struct NullOutput;
impl FileDescriptor for NullOutput {
impl FileDescription for NullOutput {
fn name(&self) -> &'static str {
"stderr and stdout"
}
@ -172,16 +159,30 @@ fn write<'tcx>(
// We just don't write anything, but report to the user that we did.
Ok(Ok(bytes.len()))
}
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(NullOutput))
#[derive(Clone, Debug)]
pub struct FileDescriptor(Rc<RefCell<Box<dyn FileDescription>>>);
impl FileDescriptor {
pub fn new<T: FileDescription>(fd: T) -> Self {
FileDescriptor(Rc::new(RefCell::new(Box::new(fd))))
}
pub fn close<'ctx>(self, communicate_allowed: bool) -> InterpResult<'ctx, io::Result<()>> {
// Destroy this `Rc` using `into_inner` so we can call `close` instead of
// implicitly running the destructor of the file description.
match Rc::into_inner(self.0) {
Some(fd) => RefCell::into_inner(fd).close(communicate_allowed),
None => Ok(Ok(())),
}
}
}
/// The file descriptor table
#[derive(Debug)]
pub struct FdTable {
pub fds: BTreeMap<i32, Box<dyn FileDescriptor>>,
pub fds: BTreeMap<i32, FileDescriptor>,
}
impl VisitProvenance for FdTable {
@ -192,28 +193,24 @@ fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
impl FdTable {
pub(crate) fn new(mute_stdout_stderr: bool) -> FdTable {
let mut fds: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new();
fds.insert(0i32, Box::new(io::stdin()));
let mut fds: BTreeMap<_, FileDescriptor> = BTreeMap::new();
fds.insert(0i32, FileDescriptor::new(io::stdin()));
if mute_stdout_stderr {
fds.insert(1i32, Box::new(NullOutput));
fds.insert(2i32, Box::new(NullOutput));
fds.insert(1i32, FileDescriptor::new(NullOutput));
fds.insert(2i32, FileDescriptor::new(NullOutput));
} else {
fds.insert(1i32, Box::new(io::stdout()));
fds.insert(2i32, Box::new(io::stderr()));
fds.insert(1i32, FileDescriptor::new(io::stdout()));
fds.insert(2i32, FileDescriptor::new(io::stderr()));
}
FdTable { fds }
}
pub fn insert_fd(&mut self, file_handle: Box<dyn FileDescriptor>) -> i32 {
pub fn insert_fd(&mut self, file_handle: FileDescriptor) -> i32 {
self.insert_fd_with_min_fd(file_handle, 0)
}
/// Insert a new FD that is at least `min_fd`.
pub fn insert_fd_with_min_fd(
&mut self,
file_handle: Box<dyn FileDescriptor>,
min_fd: i32,
) -> i32 {
pub fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptor, min_fd: i32) -> i32 {
// Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
// between used FDs, the find_map combinator will return it. If the first such unused FD
// is after all other used FDs, the find_map combinator will return None, and we will use
@ -239,15 +236,22 @@ pub fn insert_fd_with_min_fd(
new_fd
}
pub fn get(&self, fd: i32) -> Option<&dyn FileDescriptor> {
Some(&**self.fds.get(&fd)?)
pub fn get(&self, fd: i32) -> Option<Ref<'_, dyn FileDescription>> {
let fd = self.fds.get(&fd)?;
Some(Ref::map(fd.0.borrow(), |fd| fd.as_ref()))
}
pub fn get_mut(&mut self, fd: i32) -> Option<&mut dyn FileDescriptor> {
Some(&mut **self.fds.get_mut(&fd)?)
pub fn get_mut(&self, fd: i32) -> Option<RefMut<'_, dyn FileDescription>> {
let fd = self.fds.get(&fd)?;
Some(RefMut::map(fd.0.borrow_mut(), |fd| fd.as_mut()))
}
pub fn remove(&mut self, fd: i32) -> Option<Box<dyn FileDescriptor>> {
pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
let fd = self.fds.get(&fd)?;
Some(fd.clone())
}
pub fn remove(&mut self, fd: i32) -> Option<FileDescriptor> {
self.fds.remove(&fd)
}
@ -296,17 +300,8 @@ fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32>
}
let start = this.read_scalar(&args[2])?.to_i32()?;
match this.machine.fds.get_mut(fd) {
Some(file_descriptor) => {
let dup_result = file_descriptor.dup();
match dup_result {
Ok(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
Err(e) => {
this.set_last_error_from_io_error(e.kind())?;
Ok(-1)
}
}
}
match this.machine.fds.dup(fd) {
Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
None => this.fd_not_found(),
}
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
@ -330,6 +325,8 @@ fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar
Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) {
let result = file_descriptor.close(this.machine.communicate())?;
// return `0` if close is successful
let result = result.map(|()| 0i32);
this.try_unwrap_io_result(result)?
} else {
this.fd_not_found()?
@ -369,32 +366,33 @@ fn read(
.min(u64::try_from(isize::MAX).unwrap());
let communicate = this.machine.communicate();
if let Some(file_descriptor) = this.machine.fds.get_mut(fd) {
trace!("read: FD mapped to {:?}", file_descriptor);
// We want to read at most `count` bytes. We are sure that `count` is not negative
// because it was a target's `usize`. Also we are sure that its smaller than
// `usize::MAX` because it is bounded by the host's `isize`.
let mut bytes = vec![0; usize::try_from(count).unwrap()];
// `File::read` never returns a value larger than `count`,
// so this cannot fail.
let result = file_descriptor
.read(communicate, &mut bytes, *this.tcx)?
.map(|c| i64::try_from(c).unwrap());
match result {
Ok(read_bytes) => {
// If reading to `bytes` did not fail, we write those bytes to the buffer.
this.write_bytes_ptr(buf, bytes)?;
Ok(read_bytes)
}
Err(e) => {
this.set_last_error_from_io_error(e.kind())?;
Ok(-1)
}
}
} else {
let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
trace!("read: FD not found");
this.fd_not_found()
return this.fd_not_found();
};
trace!("read: FD mapped to {:?}", file_descriptor);
// We want to read at most `count` bytes. We are sure that `count` is not negative
// because it was a target's `usize`. Also we are sure that its smaller than
// `usize::MAX` because it is bounded by the host's `isize`.
let mut bytes = vec![0; usize::try_from(count).unwrap()];
// `File::read` never returns a value larger than `count`,
// so this cannot fail.
let result = file_descriptor
.read(communicate, &mut bytes, *this.tcx)?
.map(|c| i64::try_from(c).unwrap());
drop(file_descriptor);
match result {
Ok(read_bytes) => {
// If reading to `bytes` did not fail, we write those bytes to the buffer.
this.write_bytes_ptr(buf, bytes)?;
Ok(read_bytes)
}
Err(e) => {
this.set_last_error_from_io_error(e.kind())?;
Ok(-1)
}
}
}
@ -419,13 +417,15 @@ fn write(
let communicate = this.machine.communicate();
let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
if let Some(file_descriptor) = this.machine.fds.get_mut(fd) {
let result = file_descriptor
.write(communicate, &bytes, *this.tcx)?
.map(|c| i64::try_from(c).unwrap());
this.try_unwrap_io_result(result)
} else {
this.fd_not_found()
}
let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
return this.fd_not_found();
};
let result = file_descriptor
.write(communicate, &bytes, *this.tcx)?
.map(|c| i64::try_from(c).unwrap());
drop(file_descriptor);
this.try_unwrap_io_result(result)
}
}

View File

@ -17,15 +17,17 @@
use crate::*;
use shims::time::system_time_to_duration;
use self::fd::FileDescriptor;
#[derive(Debug)]
struct FileHandle {
file: File,
writable: bool,
}
impl FileDescriptor for FileHandle {
impl FileDescription for FileHandle {
fn name(&self) -> &'static str {
"FILE"
"file"
}
fn read<'tcx>(
@ -60,16 +62,14 @@ fn seek<'tcx>(
fn close<'tcx>(
self: Box<Self>,
communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
) -> InterpResult<'tcx, io::Result<()>> {
assert!(communicate_allowed, "isolation should have prevented even opening a file");
// We sync the file if it was opened in a mode different than read-only.
if self.writable {
// `File::sync_all` does the checks that are done when closing a file. We do this to
// to handle possible errors correctly.
let result = self.file.sync_all().map(|_| 0i32);
// Now we actually close the file.
drop(self);
// And return the result.
let result = self.file.sync_all();
// Now we actually close the file and return the result.
Ok(result)
} else {
// We drop the file, this closes it but ignores any errors
@ -78,16 +78,10 @@ fn close<'tcx>(
// `/dev/urandom` which are read-only. Check
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
// for a deeper discussion.
drop(self);
Ok(Ok(0))
Ok(Ok(()))
}
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
let duplicated = self.file.try_clone()?;
Ok(Box::new(FileHandle { file: duplicated, writable: self.writable }))
}
fn is_tty(&self, communicate_allowed: bool) -> bool {
communicate_allowed && self.file.is_terminal()
}
@ -399,7 +393,7 @@ fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> {
let fd = options.open(path).map(|file| {
let fh = &mut this.machine.fds;
fh.insert_fd(Box::new(FileHandle { file, writable }))
fh.insert_fd(FileDescriptor::new(FileHandle { file, writable }))
});
this.try_unwrap_io_result(fd)
@ -428,14 +422,17 @@ fn lseek64(
};
let communicate = this.machine.communicate();
Ok(Scalar::from_i64(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) {
let result = file_descriptor
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
this.try_unwrap_io_result(result)?
} else {
this.fd_not_found()?
}))
let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
return Ok(Scalar::from_i64(this.fd_not_found()?));
};
let result = file_descriptor
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
drop(file_descriptor);
let result = this.try_unwrap_io_result(result)?;
Ok(Scalar::from_i64(result))
}
fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
@ -1131,32 +1128,35 @@ fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar<Pr
return Ok(Scalar::from_i32(this.fd_not_found()?));
}
Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) {
// FIXME: Support ftruncate64 for all FDs
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!(
"`ftruncate64` is only supported on file-backed file descriptors"
)
})?;
if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
this.try_unwrap_io_result(result.map(|_| 0i32))?
} else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
-1
}
let Some(file_descriptor) = this.machine.fds.get(fd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
// FIXME: Support ftruncate64 for all FDs
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
})?;
if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
drop(file_descriptor);
let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
Ok(Scalar::from_i32(result))
} else {
// The file is not writable
drop(file_descriptor);
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
-1
Ok(Scalar::from_i32(-1))
}
} else {
this.fd_not_found()?
}))
drop(file_descriptor);
// The file is not writable
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
Ok(Scalar::from_i32(-1))
}
}
fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
@ -1190,6 +1190,7 @@ fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_all);
drop(file_descriptor);
this.try_unwrap_io_result(io_result)
}
@ -1214,6 +1215,7 @@ fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i3
err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
drop(file_descriptor);
this.try_unwrap_io_result(io_result)
}
@ -1263,6 +1265,7 @@ fn sync_file_range(
)
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
drop(file_descriptor);
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
}
@ -1498,7 +1501,8 @@ fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx
match file {
Ok(f) => {
let fh = &mut this.machine.fds;
let fd = fh.insert_fd(Box::new(FileHandle { file: f, writable: true }));
let fd =
fh.insert_fd(FileDescriptor::new(FileHandle { file: f, writable: true }));
return Ok(fd);
}
Err(e) =>
@ -1563,21 +1567,21 @@ fn from_fd<'tcx>(
ecx: &mut MiriInterpCx<'_, 'tcx>,
fd: i32,
) -> InterpResult<'tcx, Option<FileMetadata>> {
let option = ecx.machine.fds.get(fd);
let file = match option {
Some(file_descriptor) =>
&file_descriptor
.downcast_ref::<FileHandle>()
.ok_or_else(|| {
err_unsup_format!(
"obtaining metadata is only supported on file-backed file descriptors"
)
})?
.file,
None => return ecx.fd_not_found().map(|_: i32| None),
let Some(file_descriptor) = ecx.machine.fds.get(fd) else {
return ecx.fd_not_found().map(|_: i32| None);
};
let metadata = file.metadata();
let file = &file_descriptor
.downcast_ref::<FileHandle>()
.ok_or_else(|| {
err_unsup_format!(
"obtaining metadata is only supported on file-backed file descriptors"
)
})?
.file;
let metadata = file.metadata();
drop(file_descriptor);
FileMetadata::from_meta(ecx, metadata)
}

View File

@ -5,6 +5,8 @@
use crate::shims::unix::*;
use crate::*;
use self::shims::unix::fd::FileDescriptor;
/// An `Epoll` file descriptor connects file handles and epoll events
#[derive(Clone, Debug, Default)]
struct Epoll {
@ -29,22 +31,16 @@ struct EpollEvent {
data: Scalar<Provenance>,
}
impl FileDescriptor for Epoll {
impl FileDescription for Epoll {
fn name(&self) -> &'static str {
"epoll"
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
// FIXME: this is probably wrong -- check if the `dup`ed descriptor truly uses an
// independent event set.
Ok(Box::new(self.clone()))
}
fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
) -> InterpResult<'tcx, io::Result<()>> {
Ok(Ok(()))
}
}
@ -70,7 +66,7 @@ fn epoll_create1(
throw_unsup_format!("epoll_create1 flags {flags} are not implemented");
}
let fd = this.machine.fds.insert_fd(Box::new(Epoll::default()));
let fd = this.machine.fds.insert_fd(FileDescriptor::new(Epoll::default()));
Ok(Scalar::from_i32(fd))
}
@ -114,27 +110,25 @@ fn epoll_ctl(
let data = this.read_scalar(&data)?;
let event = EpollEvent { events, data };
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
let epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
let Some(mut epfd) = this.machine.fds.get_mut(epfd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
let epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
epfd.file_descriptors.insert(fd, event);
Ok(Scalar::from_i32(0))
} else {
Ok(Scalar::from_i32(this.fd_not_found()?))
}
epfd.file_descriptors.insert(fd, event);
Ok(Scalar::from_i32(0))
} else if op == epoll_ctl_del {
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
let epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
let Some(mut epfd) = this.machine.fds.get_mut(epfd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
let epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
epfd.file_descriptors.remove(&fd);
Ok(Scalar::from_i32(0))
} else {
Ok(Scalar::from_i32(this.fd_not_found()?))
}
epfd.file_descriptors.remove(&fd);
Ok(Scalar::from_i32(0))
} else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
@ -185,15 +179,14 @@ fn epoll_wait(
let _maxevents = this.read_scalar(maxevents)?.to_i32()?;
let _timeout = this.read_scalar(timeout)?.to_i32()?;
if let Some(epfd) = this.machine.fds.get_mut(epfd) {
let _epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
let Some(mut epfd) = this.machine.fds.get_mut(epfd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
let _epfd = epfd
.downcast_mut::<Epoll>()
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
// FIXME return number of events ready when scheme for marking events ready exists
throw_unsup_format!("returning ready events from epoll_wait is not yet implemented");
} else {
Ok(Scalar::from_i32(this.fd_not_found()?))
}
// FIXME return number of events ready when scheme for marking events ready exists
throw_unsup_format!("returning ready events from epoll_wait is not yet implemented");
}
}

View File

@ -8,6 +8,8 @@
use crate::shims::unix::*;
use crate::*;
use self::shims::unix::fd::FileDescriptor;
/// A kind of file descriptor created by `eventfd`.
/// The `Event` type isn't currently written to by `eventfd`.
/// The interface is meant to keep track of objects associated
@ -22,21 +24,16 @@ struct Event {
val: u64,
}
impl FileDescriptor for Event {
impl FileDescription for Event {
fn name(&self) -> &'static str {
"event"
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
// FIXME: this is wrong, the new and old FD should refer to the same event object!
Ok(Box::new(Event { val: self.val }))
}
fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
) -> InterpResult<'tcx, io::Result<()>> {
Ok(Ok(()))
}
/// A write call adds the 8-byte integer value supplied in
@ -115,7 +112,7 @@ fn eventfd(
throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported");
}
let fd = this.machine.fds.insert_fd(Box::new(Event { val: val.into() }));
let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { val: val.into() }));
Ok(Scalar::from_i32(fd))
}
}

View File

@ -13,7 +13,7 @@
mod macos;
pub use env::UnixEnvVars;
pub use fd::{FdTable, FileDescriptor};
pub use fd::{FdTable, FileDescription};
pub use fs::DirTable;
// All the Unix-specific extension traits
pub use env::EvalContextExt as _;

View File

@ -3,26 +3,24 @@
use crate::shims::unix::*;
use crate::*;
use self::fd::FileDescriptor;
/// Pair of connected sockets.
///
/// We currently don't allow sending any data through this pair, so this can be just a dummy.
#[derive(Debug)]
struct SocketPair;
impl FileDescriptor for SocketPair {
impl FileDescription for SocketPair {
fn name(&self) -> &'static str {
"socketpair"
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(SocketPair))
}
fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
) -> InterpResult<'tcx, io::Result<()>> {
Ok(Ok(()))
}
}
@ -52,9 +50,9 @@ fn socketpair(
// FIXME: fail on unsupported inputs
let fds = &mut this.machine.fds;
let sv0 = fds.insert_fd(Box::new(SocketPair));
let sv0 = fds.insert_fd(FileDescriptor::new(SocketPair));
let sv0 = Scalar::try_from_int(sv0, sv.layout.size).unwrap();
let sv1 = fds.insert_fd(Box::new(SocketPair));
let sv1 = fds.insert_fd(FileDescriptor::new(SocketPair));
let sv1 = Scalar::try_from_int(sv1, sv.layout.size).unwrap();
this.write_scalar(sv0, &sv)?;