diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ed3dd741a8be..21a413002d06 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,5 +1,6 @@ pub mod convert; +use std::any::Any; use std::cmp; use std::iter; use std::num::NonZeroUsize; @@ -23,7 +24,23 @@ use rand::RngCore; use crate::*; -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +/// A trait to work around not having trait object upcasting: +/// Add `AsAny` as supertrait and your trait objects can be turned into `&dyn Any` on which you can +/// then call `downcast`. +pub trait AsAny: Any { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} +impl AsAny for T { + #[inline(always)] + fn as_any(&self) -> &dyn Any { + self + } + #[inline(always)] + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} // This mapping should match `decode_error_kind` in // . @@ -119,6 +136,7 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) } } +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Checks if the given crate/module exists. fn have_module(&self, path: &[&str]) -> bool { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index d05c4d98fad6..1eca389e9842 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -17,7 +17,6 @@ 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::fd::epoll::Epoll; #[derive(Debug)] pub struct FileHandle { @@ -25,17 +24,9 @@ pub struct FileHandle { writable: bool, } -pub trait FileDescriptor: std::fmt::Debug { +pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny { 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, @@ -69,7 +60,9 @@ pub trait FileDescriptor: std::fmt::Debug { fn dup(&mut self) -> io::Result>; - fn is_tty(&self) -> bool; + fn is_tty(&self) -> bool { + false + } #[cfg(unix)] fn as_unix_host_fd(&self) -> Option { @@ -82,10 +75,6 @@ impl FileDescriptor for FileHandle { "FILE" } - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - Ok(self) - } - fn read<'tcx>( &mut self, communicate_allowed: bool, @@ -271,10 +260,6 @@ impl FileDescriptor for NullOutput { fn dup(&mut self) -> io::Result> { Ok(Box::new(NullOutput)) } - - fn is_tty(&self) -> bool { - false - } } #[derive(Debug)] @@ -694,7 +679,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::().ok_or_else(|| { + err_unsup_format!( + "`F_FULLFSYNC` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1530,7 +1520,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32( if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::().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); @@ -1571,7 +1566,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::().ok_or_else(|| { + err_unsup_format!("`fsync` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1593,7 +1591,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::().ok_or_else(|| { + err_unsup_format!( + "`fdatasync` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { @@ -1638,7 +1641,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::().ok_or_else(|| { + err_unsup_format!( + "`sync_data_range` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } else { @@ -1942,7 +1950,16 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => &file_descriptor.as_file_handle()?.file, + Some(file_descriptor) => + &file_descriptor + .as_any() + .downcast_ref::() + .ok_or_else(|| { + err_unsup_format!( + "obtaining metadata is only supported on file-backed file descriptors" + ) + })? + .file, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs index fd4927fa10ce..3c4a678e598d 100644 --- a/src/tools/miri/src/shims/unix/linux/fd.rs +++ b/src/tools/miri/src/shims/unix/linux/fd.rs @@ -80,7 +80,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let event = EpollEvent { events, data }; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.insert(fd, event); Ok(Scalar::from_i32(0)) @@ -89,7 +92,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } else if op == epoll_ctl_del { if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.remove(&fd); Ok(Scalar::from_i32(0)) @@ -148,7 +154,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let numevents = 0; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let _epfd = epfd.as_epoll_handle()?; + let _epfd = epfd + .as_any_mut() + .downcast_mut::() + .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 Ok(Scalar::from_i32(numevents)) diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs index e33673fecf6f..a429caaf8f41 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs @@ -32,18 +32,10 @@ impl FileDescriptor for Epoll { "epoll" } - fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> { - Ok(self) - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(self.clone())) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs index b28a6e0c56ec..1db020bb7b6d 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/event.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs @@ -28,10 +28,6 @@ impl FileDescriptor for Event { Ok(Box::new(Event { val: self.val.clone() })) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs index f9e56b4a2b40..6adae88235f3 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs @@ -19,10 +19,6 @@ impl FileDescriptor for SocketPair { Ok(Box::new(SocketPair)) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box, _communicate_allowed: bool,