Auto merge of #3770 - oli-obk:duplicator, r=oli-obk
Some FileDescriptor/FileDescription refactorings follow-up to https://github.com/rust-lang/miri/pull/3763#discussion_r1694866428 I opted not to change the method names, as I think they are already pretty good (and the common one is the short name), and the docs should explain what they actually do, but if you feel like the names you proposed would be better, I'll just do that.
This commit is contained in:
commit
cf63c16269
2 changed files with 37 additions and 33 deletions
|
|
@ -197,9 +197,13 @@ impl FileDescription for NullOutput {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileDescriptor(Rc<RefCell<Box<dyn FileDescription>>>);
|
||||
pub struct FileDescriptionRef(Rc<RefCell<Box<dyn FileDescription>>>);
|
||||
|
||||
impl FileDescriptionRef {
|
||||
fn new(fd: impl FileDescription) -> Self {
|
||||
FileDescriptionRef(Rc::new(RefCell::new(Box::new(fd))))
|
||||
}
|
||||
|
||||
impl FileDescriptor {
|
||||
pub fn borrow(&self) -> Ref<'_, dyn FileDescription> {
|
||||
Ref::map(self.0.borrow(), |fd| fd.as_ref())
|
||||
}
|
||||
|
|
@ -221,7 +225,7 @@ impl FileDescriptor {
|
|||
/// The file descriptor table
|
||||
#[derive(Debug)]
|
||||
pub struct FdTable {
|
||||
pub fds: BTreeMap<i32, FileDescriptor>,
|
||||
fds: BTreeMap<i32, FileDescriptionRef>,
|
||||
}
|
||||
|
||||
impl VisitProvenance for FdTable {
|
||||
|
|
@ -247,14 +251,14 @@ impl FdTable {
|
|||
fds
|
||||
}
|
||||
|
||||
/// Insert a file descriptor to the FdTable.
|
||||
pub fn insert_fd<T: FileDescription>(&mut self, fd: T) -> i32 {
|
||||
let file_handle = FileDescriptor(Rc::new(RefCell::new(Box::new(fd))));
|
||||
/// Insert a new file description to the FdTable.
|
||||
pub fn insert_fd(&mut self, fd: impl FileDescription) -> i32 {
|
||||
let file_handle = FileDescriptionRef::new(fd);
|
||||
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: FileDescriptor, min_fd: i32) -> i32 {
|
||||
fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptionRef, 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
|
||||
|
|
@ -290,12 +294,12 @@ impl FdTable {
|
|||
Some(fd.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
|
||||
pub fn dup(&self, fd: i32) -> Option<FileDescriptionRef> {
|
||||
let fd = self.fds.get(&fd)?;
|
||||
Some(fd.clone())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, fd: i32) -> Option<FileDescriptor> {
|
||||
pub fn remove(&mut self, fd: i32) -> Option<FileDescriptionRef> {
|
||||
self.fds.remove(&fd)
|
||||
}
|
||||
|
||||
|
|
@ -324,9 +328,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
if new_fd != old_fd {
|
||||
// Close new_fd if it is previously opened.
|
||||
// If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
|
||||
if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) {
|
||||
if let Some(file_description) = this.machine.fds.fds.insert(new_fd, dup_fd) {
|
||||
// Ignore close error (not interpreter's) according to dup2() doc.
|
||||
file_descriptor.close(this.machine.communicate())?.ok();
|
||||
file_description.close(this.machine.communicate())?.ok();
|
||||
}
|
||||
}
|
||||
Ok(new_fd)
|
||||
|
|
@ -427,10 +431,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
|
||||
let Some(file_descriptor) = this.machine.fds.remove(fd) else {
|
||||
let Some(file_description) = this.machine.fds.remove(fd) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
let result = file_descriptor.close(this.machine.communicate())?;
|
||||
let result = file_description.close(this.machine.communicate())?;
|
||||
// return `0` if close is successful
|
||||
let result = result.map(|()| 0i32);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
|
||||
|
|
|
|||
|
|
@ -576,13 +576,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
let communicate = this.machine.communicate();
|
||||
|
||||
let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
|
||||
let Some(mut file_description) = this.machine.fds.get_mut(fd) else {
|
||||
return Ok(Scalar::from_i64(this.fd_not_found()?));
|
||||
};
|
||||
let result = file_descriptor
|
||||
let result = file_description
|
||||
.seek(communicate, seek_from)?
|
||||
.map(|offset| i64::try_from(offset).unwrap());
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
|
||||
let result = this.try_unwrap_io_result(result)?;
|
||||
Ok(Scalar::from_i64(result))
|
||||
|
|
@ -1269,30 +1269,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let Some(file_descriptor) = this.machine.fds.get(fd) else {
|
||||
let Some(file_description) = 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(|| {
|
||||
file_description.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);
|
||||
drop(file_description);
|
||||
let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
|
||||
Ok(Scalar::from_i32(result))
|
||||
} else {
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
Ok(Scalar::from_i32(-1))
|
||||
}
|
||||
} else {
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
// The file is not writable
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
|
|
@ -1322,16 +1322,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
let Some(file_descriptor) = this.machine.fds.get(fd) else {
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
return Ok(this.fd_not_found()?);
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
|
||||
file_description.downcast_ref::<FileHandle>().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);
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
this.try_unwrap_io_result(io_result)
|
||||
}
|
||||
|
||||
|
|
@ -1347,16 +1347,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
return this.fd_not_found();
|
||||
}
|
||||
|
||||
let Some(file_descriptor) = this.machine.fds.get(fd) else {
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
return Ok(this.fd_not_found()?);
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
|
||||
file_description.downcast_ref::<FileHandle>().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);
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
this.try_unwrap_io_result(io_result)
|
||||
}
|
||||
|
||||
|
|
@ -1395,18 +1395,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let Some(file_descriptor) = this.machine.fds.get(fd) else {
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
|
||||
file_description.downcast_ref::<FileHandle>().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);
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
|
||||
}
|
||||
|
||||
|
|
@ -1702,11 +1702,11 @@ impl FileMetadata {
|
|||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
fd: i32,
|
||||
) -> InterpResult<'tcx, Option<FileMetadata>> {
|
||||
let Some(file_descriptor) = ecx.machine.fds.get(fd) else {
|
||||
let Some(file_description) = ecx.machine.fds.get(fd) else {
|
||||
return ecx.fd_not_found().map(|_: i32| None);
|
||||
};
|
||||
|
||||
let file = &file_descriptor
|
||||
let file = &file_description
|
||||
.downcast_ref::<FileHandle>()
|
||||
.ok_or_else(|| {
|
||||
err_unsup_format!(
|
||||
|
|
@ -1716,7 +1716,7 @@ impl FileMetadata {
|
|||
.file;
|
||||
|
||||
let metadata = file.metadata();
|
||||
drop(file_descriptor);
|
||||
drop(file_description);
|
||||
FileMetadata::from_meta(ecx, metadata)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue