add syscall dup()
This commit is contained in:
parent
9d920ed333
commit
ccc50b21c1
3 changed files with 67 additions and 0 deletions
|
@ -273,6 +273,34 @@ impl FdTable {
|
|||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match this.machine.fds.dup(old_fd) {
|
||||
Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)),
|
||||
None => this.fd_not_found(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match this.machine.fds.dup(old_fd) {
|
||||
Some(dup_fd) => {
|
||||
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) {
|
||||
// Ignore close error (not interpreter's) according to dup2() doc.
|
||||
file_descriptor.close(this.machine.communicate())?.ok();
|
||||
}
|
||||
}
|
||||
Ok(new_fd)
|
||||
}
|
||||
None => this.fd_not_found(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
|
|
|
@ -115,6 +115,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let result = this.fcntl(args)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"dup" => {
|
||||
let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
|
||||
let new_fd = this.dup(old_fd)?;
|
||||
this.write_scalar(Scalar::from_i32(new_fd), dest)?;
|
||||
}
|
||||
"dup2" => {
|
||||
let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
|
||||
let new_fd = this.read_scalar(new_fd)?.to_i32()?;
|
||||
let result = this.dup2(old_fd, new_fd)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
|
||||
// File and file system access
|
||||
"open" | "open64" => {
|
||||
|
|
|
@ -15,6 +15,7 @@ use std::path::PathBuf;
|
|||
mod utils;
|
||||
|
||||
fn main() {
|
||||
test_dup();
|
||||
test_dup_stdout_stderr();
|
||||
test_canonicalize_too_long();
|
||||
test_rename();
|
||||
|
@ -74,6 +75,31 @@ fn test_dup_stdout_stderr() {
|
|||
}
|
||||
}
|
||||
|
||||
fn test_dup() {
|
||||
let bytes = b"dup and dup2";
|
||||
let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes);
|
||||
|
||||
let mut name = path.into_os_string();
|
||||
name.push("\0");
|
||||
let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
|
||||
unsafe {
|
||||
let fd = libc::open(name_ptr, libc::O_RDONLY);
|
||||
let mut first_buf = [0u8; 4];
|
||||
libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4);
|
||||
assert_eq!(&first_buf, b"dup ");
|
||||
|
||||
let new_fd = libc::dup(fd);
|
||||
let mut second_buf = [0u8; 4];
|
||||
libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4);
|
||||
assert_eq!(&second_buf, b"and ");
|
||||
|
||||
let new_fd2 = libc::dup2(fd, 8);
|
||||
let mut third_buf = [0u8; 4];
|
||||
libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4);
|
||||
assert_eq!(&third_buf, b"dup2");
|
||||
}
|
||||
}
|
||||
|
||||
fn test_canonicalize_too_long() {
|
||||
// Make sure we get an error for long paths.
|
||||
let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap());
|
||||
|
|
Loading…
Add table
Reference in a new issue