diff --git a/src/helpers.rs b/src/helpers.rs index 766a3cba734..acc2367afa2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,6 +42,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi (AlreadyExists, "EEXIST"), (WouldBlock, "EWOULDBLOCK"), (DirectoryNotEmpty, "ENOTEMPTY"), + (FilesystemLoop, "ELOOP"), ] }; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 71824bee346..b9f3a435ea4 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -250,6 +250,19 @@ fn write_path_to_wide_str( this.write_os_str_to_wide_str(&os_str, ptr, size) } + /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, + /// adjusting path separators if needed. + fn alloc_path_as_c_str( + &mut self, + path: &Path, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.alloc_os_str_as_c_str(&os_str, memkind) + } + fn convert_path_separator<'a>( &self, os_str: Cow<'a, OsStr>, diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 76c17098791..36be1ec4f6f 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1700,7 +1700,7 @@ fn realpath( // the resolved pathname, and returns a pointer to this buffer. The // caller should deallocate this buffer using free(3)." // - this.alloc_os_str_as_c_str(resolved.as_os_str(), MiriMemoryKind::C.into())? + this.alloc_path_as_c_str(&resolved, MiriMemoryKind::C.into())? } else { let (wrote_path, _) = this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 2735e5b25bc..c7331b110e9 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -23,7 +23,6 @@ fn tmp() -> PathBuf { fn test_posix_realpath_alloc() { use std::ffi::OsString; use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; @@ -51,7 +50,6 @@ fn test_posix_realpath_alloc() { /// Test non-allocating variant of `realpath`. fn test_posix_realpath_noalloc() { use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); @@ -78,12 +76,8 @@ fn test_posix_realpath_noalloc() { /// Test failure cases for `realpath`. fn test_posix_realpath_errors() { - use std::convert::TryInto; use std::ffi::CString; - use std::fs::{create_dir_all, remove_dir_all}; use std::io::ErrorKind; - use std::os::unix::ffi::OsStrExt; - use std::os::unix::fs::symlink; // Test non-existent path returns an error. let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); @@ -92,48 +86,6 @@ fn test_posix_realpath_errors() { let e = std::io::Error::last_os_error(); assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); assert_eq!(e.kind(), ErrorKind::NotFound); - - // Test that a long path returns an error. - // - // Linux first checks if the path exists and macos does not. - // Using an existing path ensures all platforms return `ENAMETOOLONG` given a long path. - // - // Rather than creating a bunch of directories, we create two directories containing symlinks. - // Sadly we can't avoid creating directories and instead use a path like "./././././" or "./../../" as linux - // appears to collapse "." and ".." before checking path length. - let path = tmp().join("posix_realpath_errors"); - // Cleanup before test. - remove_dir_all(&path).ok(); - - // The directories we will put symlinks in. - let x = path.join("x/"); - let y = path.join("y/"); - - // The symlinks in each directory pointing to each other. - let yx_sym = y.join("x"); - let xy_sym = x.join("y"); - - // Create directories. - create_dir_all(&x).expect("dir x"); - create_dir_all(&y).expect("dir y"); - - // Create symlinks between directories. - symlink(&x, &yx_sym).expect("symlink x"); - symlink(&y, &xy_sym).expect("symlink y "); - - // This path exists due to the symlinks created above. - let too_long = path.join("x/y/".repeat(libc::PATH_MAX.try_into().unwrap())); - - let c_path = CString::new(too_long.into_os_string().as_bytes()).expect("CString::new failed"); - let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; - let e = std::io::Error::last_os_error(); - - assert!(r.is_null()); - assert_eq!(e.raw_os_error(), Some(libc::ENAMETOOLONG)); - assert_eq!(e.kind(), ErrorKind::InvalidFilename); - - // Cleanup after test. - remove_dir_all(&path).ok(); } #[cfg(any(target_os = "linux", target_os = "freebsd"))]