From 5f5ca889589c24a12864329c027db431adbc7fae Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 3 Jul 2022 10:38:49 +0100 Subject: [PATCH 1/9] Add size assert in transmute_copy --- library/core/src/mem/mod.rs | 2 ++ library/core/tests/mem.rs | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index ecd2b75ae4427..66af491607435 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1040,6 +1040,8 @@ pub fn copy(x: &T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] pub const unsafe fn transmute_copy(src: &T) -> U { + assert!(size_of::() >= size_of::(), "cannot transmute_copy if U is larger than T"); + // If U has a higher alignment requirement, src might not be suitably aligned. if align_of::() > align_of::() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 3b13dc0832fa4..6856d1a1f51ae 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -97,6 +97,46 @@ fn test_transmute_copy() { assert_eq!(1, unsafe { transmute_copy(&1) }); } +#[test] +fn test_transmute_copy_shrink() { + assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); +} + +#[test] +fn test_transmute_copy_unaligned() { + #[repr(C)] + #[derive(Default)] + struct Unaligned { + a: u8, + b: [u8; 8], + } + + let u = Unaligned::default(); + assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_transmute_copy_grow_panics() { + use std::panic; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { + let _unused: u64 = transmute_copy(&1_u8); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| { + if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) } + }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + } + } +} + #[test] #[allow(dead_code)] fn test_discriminant_send_sync() { From 13ab7962ac131733400356241c37e3ddd68d1aff Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 5 Jul 2022 07:53:27 +0100 Subject: [PATCH 2/9] `impl From for FileAttr` --- library/std/src/sys/windows/fs.rs | 37 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index e9b1006907741..b5d2b4de704a3 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -155,22 +155,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - volume_serial_number: None, - number_of_links: None, - file_index: None, - }) + Ok(self.data.into()) } } @@ -879,6 +864,26 @@ impl FileAttr { self.file_index } } +impl From for FileAttr { + fn from(wfd: c::WIN32_FIND_DATAW) -> Self { + FileAttr { + attributes: wfd.dwFileAttributes, + creation_time: wfd.ftCreationTime, + last_access_time: wfd.ftLastAccessTime, + last_write_time: wfd.ftLastWriteTime, + file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64), + reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + // reserved unless this is a reparse point + wfd.dwReserved0 + } else { + 0 + }, + volume_serial_number: None, + number_of_links: None, + file_index: None, + } + } +} fn to_u64(ft: &c::FILETIME) -> u64 { (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) From 8d4adad953edef2ef94b02e2bb1ed9b22bb1d975 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 5 Jul 2022 09:13:40 +0100 Subject: [PATCH 3/9] Windows: Use `FindFirstFileW` if `metadata` fails Usually opening a file handle with access set to metadata only will always succeed, even if the file is locked. However some special system files, such as `C:\hiberfil.sys`, are locked by the system in a way that denies even that. So as a fallback we try reading the cached metadata from the directory. --- library/std/src/fs/tests.rs | 11 +++++ library/std/src/sys/windows/fs.rs | 71 ++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e8d0132f4b98c..e1ebb1a690b0a 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1534,3 +1534,14 @@ fn read_large_dir() { entry.unwrap(); } } + +#[test] +#[cfg(windows)] +fn hiberfil_sys() { + // Get the system drive, which is usually `C:`. + let mut hiberfil = crate::env::var("SystemDrive").unwrap(); + hiberfil.push_str(r"\hiberfil.sys"); + + fs::metadata(&hiberfil).unwrap(); + fs::symlink_metadata(&hiberfil).unwrap(); +} diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index b5d2b4de704a3..4d3162f125462 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1150,22 +1150,73 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { } pub fn stat(path: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.file_attr() + metadata(path, ReparsePoint::Follow) } pub fn lstat(path: &Path) -> io::Result { + metadata(path, ReparsePoint::Open) +} + +#[repr(u32)] +#[derive(Clone, Copy, PartialEq, Eq)] +enum ReparsePoint { + Follow = 0, + Open = c::FILE_FLAG_OPEN_REPARSE_POINT, +} +impl ReparsePoint { + fn as_flag(self) -> u32 { + self as u32 + } +} + +fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - file.file_attr() + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag()); + + // Attempt to open the file normally. + // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`. + // If the fallback fails for any reason we return the original error. + match File::open(path, &opts) { + Ok(file) => file.file_attr(), + Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => { + // `ERROR_SHARING_VIOLATION` will almost never be returned. + // Usually if a file is locked you can still read some metadata. + // However, there are special system files, such as + // `C:\hiberfil.sys`, that are locked in a way that denies even that. + unsafe { + let path = maybe_verbatim(path)?; + + // `FindFirstFileW` accepts wildcard file names. + // Fortunately wildcards are not valid file names and + // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) + // therefore it's safe to assume the file name given does not + // include wildcards. + let mut wfd = mem::zeroed(); + let handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + + if handle == c::INVALID_HANDLE_VALUE { + // This can fail if the user does not have read access to the + // directory. + Err(e) + } else { + // We no longer need the find handle. + c::FindClose(handle); + + // `FindFirstFileW` reads the cached file information from the + // directory. The downside is that this metadata may be outdated. + let attrs = FileAttr::from(wfd); + if reparse == ReparsePoint::Follow && attrs.file_type().is_symlink() { + Err(e) + } else { + Ok(attrs) + } + } + } + } + Err(e) => Err(e), + } } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { From 2d0650457f570ca3d0d1ff24092e71291155a8a6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 5 Jul 2022 12:00:51 +0100 Subject: [PATCH 4/9] Add comment and simplify `hiberfil_sys` test --- library/std/src/fs/tests.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e1ebb1a690b0a..d028204e5a182 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1535,13 +1535,14 @@ fn read_large_dir() { } } +/// Test the fallback for getting the metadata of files like hiberfil.sys that +/// Windows holds a special lock on, preventing normal means of querying +/// metadata. See #96980. #[test] #[cfg(windows)] fn hiberfil_sys() { - // Get the system drive, which is usually `C:`. - let mut hiberfil = crate::env::var("SystemDrive").unwrap(); - hiberfil.push_str(r"\hiberfil.sys"); + let hiberfil = r"C:\hiberfil.sys"; - fs::metadata(&hiberfil).unwrap(); - fs::symlink_metadata(&hiberfil).unwrap(); + fs::metadata(hiberfil).unwrap(); + fs::symlink_metadata(hiberfil).unwrap(); } From 5f5bcb369730a1095d44adc9843ec80cfddea443 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 5 Jul 2022 12:23:06 +0100 Subject: [PATCH 5/9] Test if `[try_]exists` can find `hiberfil.sys` --- library/std/src/fs/tests.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index d028204e5a182..d8806b6ec60bf 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1541,8 +1541,10 @@ fn read_large_dir() { #[test] #[cfg(windows)] fn hiberfil_sys() { - let hiberfil = r"C:\hiberfil.sys"; + let hiberfil = Path::new(r"C:\hiberfil.sys"); - fs::metadata(hiberfil).unwrap(); + assert_eq!(true, hiberfil.try_exists().unwrap()); fs::symlink_metadata(hiberfil).unwrap(); + fs::metadata(hiberfil).unwrap(); + assert_eq!(true, hiberfil.exists()); } From 080a53a9533de30c614f37d006985c2f26fd30e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Jul 2022 20:43:04 -0400 Subject: [PATCH 6/9] add missing null ptr check in alloc example --- library/alloc/src/alloc.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 649aeb0890dc0..efdc86bf57a8a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -70,11 +70,14 @@ pub use std::alloc::Global; /// # Examples /// /// ``` -/// use std::alloc::{alloc, dealloc, Layout}; +/// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout}; /// /// unsafe { /// let layout = Layout::new::(); /// let ptr = alloc(layout); +/// if ptr.is_null() { +/// handle_alloc_error(layout); +/// } /// /// *(ptr as *mut u16) = 42; /// assert_eq!(*(ptr as *mut u16), 42); From 0bbcf094d7aab5106ce60c4ff77b2a732934b7ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 16 Jul 2022 20:08:04 +0000 Subject: [PATCH 7/9] Do not allow typeck children items to constrain outer RPITs --- compiler/rustc_borrowck/src/type_check/mod.rs | 29 +++++++++++++++++++ src/test/ui/impl-trait/issue-99073-2.rs | 17 +++++++++++ src/test/ui/impl-trait/issue-99073-2.stderr | 15 ++++++++++ src/test/ui/impl-trait/issue-99073.rs | 8 +++++ src/test/ui/impl-trait/issue-99073.stderr | 14 +++++++++ 5 files changed, 83 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-99073-2.rs create mode 100644 src/test/ui/impl-trait/issue-99073-2.stderr create mode 100644 src/test/ui/impl-trait/issue-99073.rs create mode 100644 src/test/ui/impl-trait/issue-99073.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf2140097e6da..1db1ec4a7bf2f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -21,6 +21,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; @@ -224,6 +225,34 @@ pub(crate) fn type_check<'mir, 'tcx>( ) .unwrap(); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + // Check that RPITs are only constrained in their outermost + // function, otherwise report a mismatched types error. + if let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::OpaqueTy(hir::OpaqueTy { + origin: + hir::OpaqueTyOrigin::AsyncFn(parent) + | hir::OpaqueTyOrigin::FnReturn(parent), + .. + }), + .. + }) = infcx.tcx.hir().get_by_def_id(opaque_type_key.def_id.expect_local()) && + parent.to_def_id() != body.source.def_id() + { + infcx + .report_mismatched_types( + &ObligationCause::misc( + hidden_type.span, + infcx.tcx.hir().local_def_id_to_hir_id( + body.source.def_id().expect_local(), + ), + ), + infcx.tcx.mk_opaque(opaque_type_key.def_id, opaque_type_key.substs), + hidden_type.ty, + ty::error::TypeError::Mismatch, + ) + .emit(); + } trace!( "finalized opaque type {:?} to {:#?}", opaque_type_key, diff --git a/src/test/ui/impl-trait/issue-99073-2.rs b/src/test/ui/impl-trait/issue-99073-2.rs new file mode 100644 index 0000000000000..bebd8286de9fe --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073-2.rs @@ -0,0 +1,17 @@ +use std::fmt::Display; + +fn main() { + test("hi", true); +} + +fn test(t: T, recurse: bool) -> impl Display { + let f = || { + let i: u32 = test::(-1, false); + //~^ ERROR mismatched types + println!("{i}"); + }; + if recurse { + f(); + } + t +} diff --git a/src/test/ui/impl-trait/issue-99073-2.stderr b/src/test/ui/impl-trait/issue-99073-2.stderr new file mode 100644 index 0000000000000..c1e4b823c08e7 --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073-2.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-99073-2.rs:9:22 + | +LL | fn test(t: T, recurse: bool) -> impl Display { + | ------------ the expected opaque type +LL | let f = || { +LL | let i: u32 = test::(-1, false); + | ^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issue-99073.rs b/src/test/ui/impl-trait/issue-99073.rs new file mode 100644 index 0000000000000..1d75f6086664f --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = fix(|_: &dyn Fn()| {}); +} + +fn fix(f: F) -> impl Fn() { + move || f(fix(&f)) + //~^ ERROR mismatched types +} diff --git a/src/test/ui/impl-trait/issue-99073.stderr b/src/test/ui/impl-trait/issue-99073.stderr new file mode 100644 index 0000000000000..b35d58093d5fc --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-99073.rs:6:13 + | +LL | fn fix(f: F) -> impl Fn() { + | --------- the expected opaque type +LL | move || f(fix(&f)) + | ^^^^^^^^^^ types differ + | + = note: expected opaque type `impl Fn()` + found type parameter `G` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From e6be52bbbde9043385ecc5a4e2460fa85daba9c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:47:34 -0400 Subject: [PATCH 8/9] interpret/visitor: add missing early return --- compiler/rustc_const_eval/src/interpret/visitor.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index f6a0c19d25953..3f6e8a8f755a1 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -473,6 +473,9 @@ macro_rules! make_value_visitor { // The second `Box` field is the allocator, which we recursively check for validity // like in regular structs. self.visit_field(v, 1, &alloc)?; + + // We visited all parts of this one. + return Ok(()); } _ => {}, }; From 273b977305ce2f87aeda99b8bd9dbc87d3af8dd4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 17 Jul 2022 10:37:23 -0700 Subject: [PATCH 9/9] use opaque_ty_origin_unchecked instead of destructuring HIR --- compiler/rustc_borrowck/src/type_check/mod.rs | 14 +++----------- compiler/rustc_infer/src/infer/opaque_types.rs | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 1db1ec4a7bf2f..aa4a632c15076 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -227,17 +227,9 @@ pub(crate) fn type_check<'mir, 'tcx>( let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); // Check that RPITs are only constrained in their outermost // function, otherwise report a mismatched types error. - if let hir::Node::Item(hir::Item { - kind: - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: - hir::OpaqueTyOrigin::AsyncFn(parent) - | hir::OpaqueTyOrigin::FnReturn(parent), - .. - }), - .. - }) = infcx.tcx.hir().get_by_def_id(opaque_type_key.def_id.expect_local()) && - parent.to_def_id() != body.source.def_id() + if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent) + = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span) + && parent.to_def_id() != body.source.def_id() { infcx .report_mismatched_types( diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index f11701bba6f43..e8d2d628c6652 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin { + pub fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin { let def_id = opaque_def_id.as_local().unwrap(); let origin = match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,