output realpath as a path, and remove a bogus test

This commit is contained in:
Ralf Jung 2022-08-02 18:08:43 -04:00
parent b43bede938
commit 8356f4cc23
4 changed files with 15 additions and 49 deletions

View File

@ -42,6 +42,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
(AlreadyExists, "EEXIST"), (AlreadyExists, "EEXIST"),
(WouldBlock, "EWOULDBLOCK"), (WouldBlock, "EWOULDBLOCK"),
(DirectoryNotEmpty, "ENOTEMPTY"), (DirectoryNotEmpty, "ENOTEMPTY"),
(FilesystemLoop, "ELOOP"),
] ]
}; };

View File

@ -250,6 +250,19 @@ fn write_path_to_wide_str(
this.write_os_str_to_wide_str(&os_str, ptr, size) 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<MiriMemoryKind>,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
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>( fn convert_path_separator<'a>(
&self, &self,
os_str: Cow<'a, OsStr>, os_str: Cow<'a, OsStr>,

View File

@ -1700,7 +1700,7 @@ fn realpath(
// the resolved pathname, and returns a pointer to this buffer. The // the resolved pathname, and returns a pointer to this buffer. The
// caller should deallocate this buffer using free(3)." // caller should deallocate this buffer using free(3)."
// <https://man7.org/linux/man-pages/man3/realpath.3.html> // <https://man7.org/linux/man-pages/man3/realpath.3.html>
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 { } else {
let (wrote_path, _) = let (wrote_path, _) =
this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; this.write_path_to_c_str(&resolved, processed_ptr, path_max)?;

View File

@ -23,7 +23,6 @@ fn tmp() -> PathBuf {
fn test_posix_realpath_alloc() { fn test_posix_realpath_alloc() {
use std::ffi::OsString; use std::ffi::OsString;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::fs::{remove_file, File};
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::os::unix::ffi::OsStringExt; use std::os::unix::ffi::OsStringExt;
@ -51,7 +50,6 @@ fn test_posix_realpath_alloc() {
/// Test non-allocating variant of `realpath`. /// Test non-allocating variant of `realpath`.
fn test_posix_realpath_noalloc() { fn test_posix_realpath_noalloc() {
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::fs::{remove_file, File};
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); let path = tmp().join("miri_test_libc_posix_realpath_noalloc");
@ -78,12 +76,8 @@ fn test_posix_realpath_noalloc() {
/// Test failure cases for `realpath`. /// Test failure cases for `realpath`.
fn test_posix_realpath_errors() { fn test_posix_realpath_errors() {
use std::convert::TryInto;
use std::ffi::CString; use std::ffi::CString;
use std::fs::{create_dir_all, remove_dir_all};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::symlink;
// Test non-existent path returns an error. // Test non-existent path returns an error.
let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); 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(); let e = std::io::Error::last_os_error();
assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); assert_eq!(e.raw_os_error(), Some(libc::ENOENT));
assert_eq!(e.kind(), ErrorKind::NotFound); 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"))] #[cfg(any(target_os = "linux", target_os = "freebsd"))]