From 38204b63211302a77bb9ff677f6b1df9f5acd734 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 16:45:05 -0600 Subject: [PATCH 1/3] Add shim for rename --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 28 +++++++++++++++++++++++++++- tests/run-pass/fs.rs | 14 +++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b40f3c6906..2fd886ed0e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -521,6 +521,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "rename" => { + let result = this.rename(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f0efc073f75..2ae215e7204 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_file, File, OpenOptions}; +use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -582,6 +582,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_last_error(ebadf)?; Ok((-1).into()) } + + fn rename( + &mut self, + oldpath_op: OpTy<'tcx, Tag>, + newpath_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("rename")?; + + let oldpath_scalar = this.read_scalar(oldpath_op)?.not_undef()?; + let newpath_scalar = this.read_scalar(newpath_op)?.not_undef()?; + + if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { + let efault = this.eval_libc("EFAULT")?; + this.set_last_error(efault)?; + return Ok(-1); + } + + let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; + let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + + let result = rename(oldpath, newpath).map(|_| 0); + + this.try_unwrap_io_result(result) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7483bf3ec8b..9e1891adf34 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, remove_file}; +use std::fs::{File, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -82,6 +82,18 @@ fn main() { // Removing file should succeed. remove_file(&path).unwrap(); + // Renaming a file should succeed. + let path1 = tmp.join("rename_source.txt"); + let path2 = tmp.join("rename_destination.txt"); + // Clean files for robustness. + remove_file(&path1).ok(); + remove_file(&path2).ok(); + let file = File::create(&path1).unwrap(); + drop(file); + rename(&path1, &path2).unwrap(); + assert!(path2.metadata().unwrap().is_file()); + remove_file(&path2).ok(); + // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); From f7e085764445c679bdc2694733119f2b5aeedf8e Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 22:40:46 -0600 Subject: [PATCH 2/3] Test that src path of rename is no longer a file --- tests/run-pass/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9e1891adf34..e9132fbd61d 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -91,6 +91,7 @@ fn main() { let file = File::create(&path1).unwrap(); drop(file); rename(&path1, &path2).unwrap(); + assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); remove_file(&path2).ok(); From 91868125a519db341f86410590b959b10de03f11 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 14 Feb 2020 08:19:16 -0600 Subject: [PATCH 3/3] Removing file after rename must succeed Co-Authored-By: Ralf Jung --- tests/run-pass/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index e9132fbd61d..71c6e854f7c 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -93,7 +93,7 @@ fn main() { rename(&path1, &path2).unwrap(); assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); - remove_file(&path2).ok(); + remove_file(&path2).unwrap(); // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error.