-
Notifications
You must be signed in to change notification settings - Fork 318
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #2609 - RalfJung:is_terminal, r=RalfJung
Use is_terminal to implement isatty This means that Linux targets on Windows hosts should give a correct reply. We still don't have an implementation for Windows targets though, that requires some tracking of handles. Fixes #2419 Also restructure our `fs` tests a bit to test the parts that don't need libc separately. `as_unix_host_fd` is now not used any more, but it could become useful again in the future so I kept it.
- Loading branch information
Showing
13 changed files
with
230 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//@ignore-target-windows: no libc on Windows | ||
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace | ||
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" | ||
|
||
use std::ffi::CString; | ||
use std::fs; | ||
use std::io::{Error, ErrorKind}; | ||
|
||
fn main() { | ||
// test `fcntl` | ||
unsafe { | ||
assert_eq!(libc::fcntl(1, libc::F_DUPFD, 0), -1); | ||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EPERM)); | ||
} | ||
|
||
// test `readlink` | ||
let symlink_c_str = CString::new("foo.txt").unwrap(); | ||
let mut buf = vec![0; "foo_link.txt".len() + 1]; | ||
unsafe { | ||
assert_eq!(libc::readlink(symlink_c_str.as_ptr(), buf.as_mut_ptr(), buf.len()), -1); | ||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); | ||
} | ||
|
||
// test `stat` | ||
assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); | ||
// check that it is the right kind of `PermissionDenied` | ||
assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
warning: `fcntl` was made to return an error due to isolation | ||
|
||
warning: `readlink` was made to return an error due to isolation | ||
|
||
warning: `$STAT` was made to return an error due to isolation | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
//@ignore-target-windows: no libc on Windows | ||
//@compile-flags: -Zmiri-disable-isolation | ||
|
||
#![feature(io_error_more)] | ||
#![feature(io_error_uncategorized)] | ||
|
||
use std::convert::TryInto; | ||
use std::ffi::CString; | ||
use std::fs::{canonicalize, remove_file, File}; | ||
use std::io::{Error, ErrorKind, Write}; | ||
use std::os::unix::ffi::OsStrExt; | ||
use std::path::PathBuf; | ||
|
||
fn main() { | ||
test_dup_stdout_stderr(); | ||
test_canonicalize_too_long(); | ||
test_readlink(); | ||
test_file_open_unix_allow_two_args(); | ||
test_file_open_unix_needs_three_args(); | ||
test_file_open_unix_extra_third_arg(); | ||
} | ||
|
||
fn tmp() -> PathBuf { | ||
std::env::var("MIRI_TEMP") | ||
.map(|tmp| { | ||
// MIRI_TEMP is set outside of our emulated | ||
// program, so it may have path separators that don't | ||
// correspond to our target platform. We normalize them here | ||
// before constructing a `PathBuf` | ||
|
||
#[cfg(windows)] | ||
return PathBuf::from(tmp.replace("/", "\\")); | ||
|
||
#[cfg(not(windows))] | ||
return PathBuf::from(tmp.replace("\\", "/")); | ||
}) | ||
.unwrap_or_else(|_| std::env::temp_dir()) | ||
} | ||
|
||
/// Prepare: compute filename and make sure the file does not exist. | ||
fn prepare(filename: &str) -> PathBuf { | ||
let path = tmp().join(filename); | ||
// Clean the paths for robustness. | ||
remove_file(&path).ok(); | ||
path | ||
} | ||
|
||
/// Prepare like above, and also write some initial content to the file. | ||
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { | ||
let path = prepare(filename); | ||
let mut file = File::create(&path).unwrap(); | ||
file.write(content).unwrap(); | ||
path | ||
} | ||
|
||
fn test_file_open_unix_allow_two_args() { | ||
let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); | ||
|
||
let mut name = path.into_os_string(); | ||
name.push("\0"); | ||
let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>(); | ||
let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY) }; | ||
} | ||
|
||
fn test_file_open_unix_needs_three_args() { | ||
let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); | ||
|
||
let mut name = path.into_os_string(); | ||
name.push("\0"); | ||
let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>(); | ||
let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT, 0o666) }; | ||
} | ||
|
||
fn test_file_open_unix_extra_third_arg() { | ||
let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); | ||
|
||
let mut name = path.into_os_string(); | ||
name.push("\0"); | ||
let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>(); | ||
let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 42) }; | ||
} | ||
|
||
fn test_dup_stdout_stderr() { | ||
let bytes = b"hello dup fd\n"; | ||
unsafe { | ||
let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); | ||
let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); | ||
libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); | ||
libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); | ||
} | ||
} | ||
|
||
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()); | ||
assert!(canonicalize(too_long).is_err()); | ||
} | ||
|
||
fn test_readlink() { | ||
let bytes = b"Hello, World!\n"; | ||
let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); | ||
let expected_path = path.as_os_str().as_bytes(); | ||
|
||
let symlink_path = prepare("miri_test_fs_symlink.txt"); | ||
std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); | ||
|
||
// Test that the expected string gets written to a buffer of proper | ||
// length, and that a trailing null byte is not written. | ||
let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); | ||
let symlink_c_ptr = symlink_c_str.as_ptr(); | ||
|
||
// Make the buf one byte larger than it needs to be, | ||
// and check that the last byte is not overwritten. | ||
let mut large_buf = vec![0xFF; expected_path.len() + 1]; | ||
let res = | ||
unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; | ||
// Check that the resovled path was properly written into the buf. | ||
assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); | ||
assert_eq!(large_buf.last(), Some(&0xFF)); | ||
assert_eq!(res, large_buf.len() as isize - 1); | ||
|
||
// Test that the resolved path is truncated if the provided buffer | ||
// is too small. | ||
let mut small_buf = [0u8; 2]; | ||
let res = | ||
unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; | ||
assert_eq!(small_buf, &expected_path[..small_buf.len()]); | ||
assert_eq!(res, small_buf.len() as isize); | ||
|
||
// Test that we report a proper error for a missing path. | ||
let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); | ||
let res = unsafe { | ||
libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) | ||
}; | ||
assert_eq!(res, -1); | ||
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
hello dup fd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 0 additions & 4 deletions
4
...s/pass-dep/shims/fs_with_isolation.stderr → tests/pass/shims/fs-with-isolation.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.