diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3..9d025b2b7b24 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -489,6 +489,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "unlink" => { let result = this.unlink(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a7cf9d31c0b..4cfff9446b85 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, File, OpenOptions}; -use std::io::{Read, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -264,6 +264,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn lseek64( + &mut self, + fd_op: OpTy<'tcx, Tag>, + offset_op: OpTy<'tcx, Tag>, + whence_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + this.check_no_isolation("lseek64")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let offset = this.read_scalar(offset_op)?.to_i64()?; + let whence = this.read_scalar(whence_op)?.to_i32()?; + + let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? { + SeekFrom::Start(offset as u64) + } else if whence == this.eval_libc_i32("SEEK_CUR")? { + SeekFrom::Current(offset) + } else if whence == this.eval_libc_i32("SEEK_END")? { + SeekFrom::End(offset) + } else { + throw_unsup_format!("Unsupported whence argument to lseek64: {}", whence) + }; + + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let result = handle.file.seek(seek_from).map(|offset| offset as i64); + this.try_unwrap_io_result(result) + } else { + this.handle_not_found() + } + } + fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7..4da67369aef8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write, ErrorKind, Result}; +use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -40,6 +40,12 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test that seeking to the beginning and reading until EOF gets the text again. + file.seek(SeekFrom::Start(0)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct.