Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3647,11 +3647,14 @@ pub enum Polonius {

impl Default for Polonius {
fn default() -> Self {
if option_env!("CFG_DEFAULT_POLONIUS_NEXT").is_some() { Self::Next } else { Self::Off }
Self::DEFAULT
}
}

impl Polonius {
pub(crate) const DEFAULT: Self =
if option_env!("CFG_DEFAULT_POLONIUS_NEXT").is_some() { Self::Next } else { Self::Off };

/// Returns whether the legacy version of polonius is enabled
pub fn is_legacy_enabled(&self) -> bool {
matches!(self, Polonius::Legacy)
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ macro_rules! options {
$( { TARGET_MODIFIER: $tmod_variant:ident } )?
$( { MITIGATION: $mitigation_variant:ident } )?
,
$desc:literal
$desc:expr
$(, removed: $removed:ident )?
),
)*
Expand Down Expand Up @@ -2350,6 +2350,12 @@ options! {
// - src/doc/rustc/src/codegen-options/index.md
}

const POLONIUS_HELP: &str = match Polonius::DEFAULT {
Polonius::Off => "enable polonius-based borrow-checker (default: no)",
Polonius::Next => "enable polonius-based borrow-checker (default: next)",
Polonius::Legacy => panic!("Polonius::Legacy is not a valid default value"),
};

options! {
UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",

Expand Down Expand Up @@ -2750,7 +2756,7 @@ options! {
`vt-ptr-type-discrimination - incorporate type discrimination in authenticated vtable pointers
Example: `-Zpointer-authentication=+calls,-init-fini`."),
polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
"enable polonius-based borrow-checker (default: no)"),
POLONIUS_HELP),
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to prepend the linker invocation (can be used several times)"),
pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
Expand Down
32 changes: 15 additions & 17 deletions library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3620,22 +3620,22 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
///
/// # Platform-specific behavior
///
/// This function currently corresponds to:
/// * `open` with `O_NOFOLLOW` flag enabled + `fchmod` on WASI
/// * `fchmodat` function with the flag `AT_SYMLINK_NOFOLLOW` enabled
/// on Unix platforms
/// * The flag `FILE_FLAG_OPEN_REPARSE_POINT` is enabled and then the
/// permissions of the file is set through `SetFileInformationByHandle`
/// on Windows.
/// * On all other platforms, the behavior remains the same with
/// [`fs::set_permissions`].
///
/// [`fs::set_permissions`]: crate::fs::set_permissions
/// This function currently corresponds to the following underlying operations:
/// * Android: returns [`Unsupported`] on all files.
/// * Linux, BSD-based platforms, QNX, NTO: `fchmodat` with `AT_SYMLINK_NOFOLLOW`.
/// If that is not supported, we fall back to:
/// * Unix-based platforms with symlinks: `open` with `O_NOFOLLOW` followed by
/// [`fs::set_permissions`].
/// * Unix-based platforms without symlinks: `open` followed by [`fs::set_permissions`].
/// * Windows: `CreateFileW` with `FILE_FLAG_OPEN_REPARSE_POINT` followed
/// by `SetFileInformationByHandle`.
///
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// [`fs::set_permissions`]: crate::fs::set_permissions
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
Expand All @@ -3644,10 +3644,8 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
/// * `path` does not exist.
/// * The user lacks the permission to change attributes of the file.
///
/// Note: On Linux, this will result in a [`Unsupported`] error
/// if the final element is a symlink. On BSD-based systems, the
/// behavior can vary from symlink permission bits changing or
/// there being no effects on symlinks
/// Note: On Linux and other Unix-based platforms with symlinks (non-BSD-based),
/// this will result in an [`Unsupported`] error if the final element is a symlink.
///
/// [`Unsupported`]: crate::io::ErrorKind::Unsupported
///
Expand All @@ -3660,8 +3658,8 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
/// fn main() -> std::io::Result<()> {
/// let mut perms = fs::symlink_metadata("foo.txt")?.permissions();
/// perms.set_readonly(true);
/// // This should result in an error on certain platforms
/// // or succeed in modifying the permissions of a symlink
/// // This should result in an error on certain platforms or
/// // succeed in modifying the permissions of a symlink
/// fs::set_permissions_nofollow("foo.txt", perms)?;
/// Ok(())
/// }
Expand Down
59 changes: 38 additions & 21 deletions library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ fn set_get_unix_permissions() {
assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
}

#[cfg(not(target_os = "android"))]
#[test]
fn set_get_permissions_nofollows() {
let tmpdir = tmpdir();
Expand Down Expand Up @@ -649,56 +650,71 @@ fn set_get_permissions_nofollows() {

// Only Windows and Unix support `fs::set_permissions_nofollow`
#[test]
#[cfg(all(any(windows, unix), not(any(target_os = "espidf", target_os = "horizon"))))]
#[cfg(all(
any(windows, unix),
not(any(target_os = "espidf", target_os = "horizon", target_os = "wasi"))
))]
fn set_get_permissions_nofollows_symlink() {
#[cfg(not(windows))]
use crate::os::unix::fs::symlink as symlink_dir;
use crate::os::unix::fs::symlink as symlink_file;
#[cfg(windows)]
use crate::os::windows::fs::symlink_dir;
use crate::os::windows::fs::symlink_file;

let tmpdir = tmpdir();
let filename = tmpdir.join("set_get_unix_permissions_file");
let symlink_name = tmpdir.join("set_get_unix_permissions");
check!(File::create(&filename));
check!(symlink_dir(&filename, &symlink_name));
check!(symlink_file(&filename, &symlink_name));

let sym_metadata = check!(fs::symlink_metadata(&symlink_name));
let mut permission_bits = sym_metadata.permissions();
permission_bits.set_readonly(true);
let result = fs::set_permissions_nofollow(&symlink_name, permission_bits);
let init_symlink_metadata = check!(fs::symlink_metadata(&symlink_name));
let mut init_symlink_permissions = init_symlink_metadata.permissions();

let init_target_metadata = check!(fs::metadata(&symlink_name));
let init_target_permissions = init_target_metadata.permissions();

// Set symlink permissions to readonly
init_symlink_permissions.set_readonly(true);
let result = fs::set_permissions_nofollow(&symlink_name, init_symlink_permissions);

cfg_select! {
any(
windows,
target_os = "android",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
target_os = "dragonfly",
target_os = "nto",
target_os = "qnx"
) => {
assert_eq!(result.unwrap(), ());
let metadata0 = check!(fs::symlink_metadata(&symlink_name));
// So seems like BSD-based systems trying to set permissions
// on symlinks could lead to no effect, so we should expect
// there being no change to BSD-based systems.

let after_target_metadata = check!(fs::metadata(&symlink_name));
// We should expect the target file to not have its permission bits
// changed
assert_eq!(after_target_metadata.permissions(), init_target_permissions);

let after_symlink_metadata = check!(fs::symlink_metadata(&symlink_name));
// On these systems, it's confirmed the symlink itself is marked readonly
// https://superuser.com/questions/1099634/change-permissions-symbolic-link-mac-os
#[cfg(windows)]
assert!(metadata0.permissions().readonly());
#[cfg(not(windows))]
assert!(!metadata0.permissions().readonly());
assert!(after_symlink_metadata.permissions().readonly());

// Reset the read-only bit under Windows 7: avoids the
// `TempDir::drop` from crashing on a permission denial when
// trying to delete the file that has it.
#[cfg(all(windows, target_vendor = "win7"))]
{
let mut permission_bits = metadata0.permissions();
permission_bits.set_readonly(false);
check!(fs::set_permissions_nofollow(&symlink_name, permission_bits));
let mut symlink_permission_bits = after_symlink_metadata.permissions();
symlink_permission_bits.set_readonly(false);
check!(fs::set_permissions_nofollow(&symlink_name, symlink_permission_bits));
}
}
_ => {
let after_target_metadata = check!(fs::metadata(&symlink_name));
// We should expect the target file to not have its permission bits
// changed
assert_eq!(after_target_metadata.permissions(), init_target_permissions);

let error_kind = result.unwrap_err().kind();
assert_eq!(error_kind, crate::io::ErrorKind::Unsupported);
}
Expand Down Expand Up @@ -1426,6 +1442,7 @@ fn fchmod_works() {
check!(file.set_permissions(p));
}

#[cfg(not(target_os = "android"))]
#[test]
fn fchmodat_works() {
let tmpdir = tmpdir();
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2377,7 +2377,7 @@ pub struct NormalizeError;
impl Path {
// The following (private!) function allows construction of a path from a u8
// slice, which is only safe when it is known to follow the OsStr encoding.
unsafe fn from_u8_slice(s: &[u8]) -> &Path {
pub(crate) unsafe fn from_u8_slice(s: &[u8]) -> &Path {
unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) }
}
// The following (private!) function reveals the byte encoding used for OsStr.
Expand Down
100 changes: 80 additions & 20 deletions library/std/src/sys/fs/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1884,31 +1884,91 @@ pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> {
cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ())
}

#[cfg(target_os = "android")]
pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> {
// Currently Android seems to be having inconsistent behavior with fchmodat
// with `AT_SYMLINK_NOFOLLOW` or openat with `O_NOFOLLOW` + fchmod.
// See this issue here mentioning inconsistent behavior on fchmodat:
// https://github.com/android/ndk/issues/1258
// On the arm-android CI job, using fchmodat with `AT_SYMLINK_NOFOLLOW` +
// fallback behavior on a symlink sets the target file's permissions,
// which is incorrect behavior.
Err(crate::io::ErrorKind::Unsupported.into())
}

#[cfg(not(target_os = "android"))]
pub fn set_perm_nofollow(p: &CStr, perm: FilePermissions) -> io::Result<()> {
// ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it.
// Their filesystems do not have symbolic links, so no special handling is required.
cfg_select! {
// wasm32-wasip1 targets do not support fchmodat, so we fall down to
// open + fchmod
target_os = "wasi" => {
use crate::fs::{OpenOptions, Permissions};
use crate::os::wasi::ffi::OsStrExt;
use crate::os::wasi::fs::OpenOptionsExt;
#[inline]
/// Helper function for fallback open with `O_NOFOLLOW` + `fchmod` behavior
fn open_and_set_permissions(p: &CStr, perm: FilePermissions) -> io::Result<()> {
use crate::fs::{OpenOptions, Permissions};

let mut options = OpenOptions::new();
options.custom_flags(libc::O_NOFOLLOW);
let mut options = OpenOptions::new();

let bytes = p.to_bytes();
let os_str = OsStr::from_bytes(bytes);
options.open(Path::new(os_str))?.set_permissions(Permissions::from_inner(perm))
// ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it.
// Their filesystems do not have symbolic links, so no special handling is required.
#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
{
#[cfg(not(target_os = "wasi"))]
use crate::os::unix::fs::OpenOptionsExt;
#[cfg(target_os = "wasi")]
use crate::os::wasi::fs::OpenOptionsExt;
options.read(true).custom_flags(libc::O_NOFOLLOW);
}
all(target_os = "linux", not(any(target_os = "espidf", target_os = "horizon"))) => {
cvt_r(|| unsafe {
libc::fchmodat(libc::AT_FDCWD, p.as_ptr(), perm.mode, libc::AT_SYMLINK_NOFOLLOW)
})
.map(|_| ())

// SAFETY: Since this function is called with `with_native_path`
// and that successfully converted the `&Path` to a `CString`,
// it should be safe to convert the `&CStr` back to a `Path`.
let os_str = unsafe { OsStr::from_encoded_bytes_unchecked(p.to_bytes()) };
options.open(Path::new(os_str))?.set_permissions(Permissions::from_inner(perm))
}

// This res value is modified for platforms that support the `fchmodat` syscall.
#[allow(unused)]
let mut res: Result<(), core::io::Error> = Err(crate::io::ErrorKind::Unsupported.into());

// These platforms support `fchmodat`, so utilize this syscall over `open` + `fchmod`
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "nto",
target_os = "qnx"
))]
{
res = cvt_r(|| unsafe {
libc::fchmodat(libc::AT_FDCWD, p.as_ptr(), perm.mode, libc::AT_SYMLINK_NOFOLLOW)
})
.map(|_| ());
}

// If fchmodat fails with `ErrorKind::Unsupported` fallback to using open + fchmod. This is just in case
// for older systems like Ubuntu 20.04 where fchmodat fails with EOPNOTSUPP on both regular files and
// symlinks when AT_SYMLINK_NOFOLLOW is passed in.
match res {
Ok(_) => Ok(()),
Err(err) => {
if err.kind() == crate::io::ErrorKind::Unsupported {
match open_and_set_permissions(p, perm) {
Ok(_) => return Ok(()),
Err(e) => {
if e.kind() == crate::io::ErrorKind::FilesystemLoop {
// When open is used with O_NOFOLLOW flag, if the trailing component of
// a path is a symbolic link, it should fail with ELOOP error. Instead of
// returning `FilesystemLoop`, this returns `Unsupported` to keep it consistent
// with what `fchmodat` would return when chmoding a symlink using AT_SYMLINK_NOFOLLOW.
return Err(err);
}
return Err(e);
}
}
}

Err(err)
}
_ => cvt_r(|| unsafe { libc::fchmodat(libc::AT_FDCWD, p.as_ptr(), perm.mode, 0) }).map(|_| ()),
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/run-make/rustc-help/polonius-help-stable.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Z polonius=val -- enable polonius-based borrow-checker (default: no)
1 change: 1 addition & 0 deletions tests/run-make/rustc-help/polonius-help.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Z polonius=val -- enable polonius-based borrow-checker (default: next)
15 changes: 15 additions & 0 deletions tests/run-make/rustc-help/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use run_make_support::{bare_rustc, diff, similar};
fn main() {
// `rustc --help`
let help = bare_rustc().arg("--help").run().stdout_utf8();

diff().expected_file("help.stdout").actual_text("(rustc --help)", &help).run();

// `rustc` should be the same as `rustc --help`
Expand All @@ -22,6 +23,20 @@ fn main() {
// Check that all help options can be invoked at once
let codegen_help = bare_rustc().arg("-Chelp").run().stdout_utf8();
let unstable_help = bare_rustc().arg("-Zhelp").run().stdout_utf8();

let polonius_help =
format!("{}\n", unstable_help.lines().find(|line| line.contains("polonius=val")).unwrap());
let version = bare_rustc().arg("--version").run().stdout_utf8();
let expected_file = if version.contains("-nightly") || version.contains("-dev") {
"polonius-help.stdout"
} else {
"polonius-help-stable.stdout"
};
diff()
.expected_file(expected_file)
.actual_text("rustc -Zhelp (polonius)", &polonius_help)
.run();

let lints_help = bare_rustc().arg("-Whelp").run().stdout_utf8();
let expected_all = format!("{help}{codegen_help}{unstable_help}{lints_help}");
let all_help = bare_rustc().args(["--help", "-Chelp", "-Zhelp", "-Whelp"]).run().stdout_utf8();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Regression test for https://github.com/rust-lang/rust/issues/143896.

trait TraitA<'a> {
const K: usize = 0;
}

impl<T> TraitA<'_> for () {}
//~^ ERROR the type parameter `T` is not constrained

impl dyn TraitA<'_> where (): TraitA<'a, K = 0> {}
//~^ ERROR use of undeclared lifetime name `'a`
//~| ERROR associated const equality is incomplete

pub fn main() {}
Loading
Loading