diff --git a/RELEASES.md b/RELEASES.md index 18492213a5dd3..f5b71f295c629 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Compiler - [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] - [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] - [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] +- [Dropped support for all cloudabi targets.][78439] \* Refer to Rust's [platform support page][forge-platform-support] for more information on Rust's tiered platform support. @@ -77,7 +78,6 @@ Compatibility Notes - [`#![test]` as an inner attribute is now considered unstable like other inner macro attributes, and reports an error by default through the `soft_unstable` lint.][79003] - [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] -- [Dropped support for all cloudabi targets.][78439] - [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's recommended to use the `#[panic_handler]` attribute to provide your own implementation. - [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a78d692aaa7fb..26111729ba5b2 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V if enabled.contains(SanitizerSet::THREAD) { llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); } + if enabled.contains(SanitizerSet::HWADDRESS) { + llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn); + } } /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 326ae354ccf48..8b737c9a2e557 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -440,6 +440,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY), sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int, sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD), + sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS), + sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS), }) } else { None @@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static if config.sanitizer.contains(SanitizerSet::THREAD) { passes.push(llvm::LLVMRustCreateThreadSanitizerPass()); } + if config.sanitizer.contains(SanitizerSet::HWADDRESS) { + let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS); + passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover)); + } } pub(crate) fn link( diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e82198f8f0c06..8c1740d8f25f0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -131,6 +131,7 @@ pub enum Attribute { ReturnsTwice = 25, ReadNone = 26, InaccessibleMemOnly = 27, + SanitizeHWAddress = 28, } /// LLVMIntPredicate @@ -439,6 +440,8 @@ pub struct SanitizerOptions { pub sanitize_memory_recover: bool, pub sanitize_memory_track_origins: c_int, pub sanitize_thread: bool, + pub sanitize_hwaddress: bool, + pub sanitize_hwaddress_recover: bool, } /// LLVMRelocMode @@ -2128,6 +2131,7 @@ extern "C" { Recover: bool, ) -> &'static mut Pass; pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass; + pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass; pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass); pub fn LLVMRustAddLastExtensionPasses( PMB: &PassManagerBuilder, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8bc4e64422370..6c58417590e69 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke if sanitizer.contains(SanitizerSet::THREAD) { link_sanitizer_runtime(sess, linker, "tsan"); } + if sanitizer.contains(SanitizerSet::HWADDRESS) { + link_sanitizer_runtime(sess, linker, "hwasan"); + } } fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 57b8664d3b605..0e3bf5615af7b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -85,6 +85,7 @@ enum LLVMRustAttribute { ReturnsTwice = 25, ReadNone = 26, InaccessibleMemOnly = 27, + SanitizeHWAddress = 28, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 2264908995bb7..5263d5dcf3e8f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" +#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" @@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() { return wrap(createThreadSanitizerLegacyPassPass()); } +extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) { + const bool CompileKernel = false; + + return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover)); +} + extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) { assert(RustPass); Pass *Pass = unwrap(RustPass); @@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions { bool SanitizeMemoryRecover; int SanitizeMemoryTrackOrigins; bool SanitizeThread; + bool SanitizeHWAddress; + bool SanitizeHWAddressRecover; }; extern "C" void @@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager( /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); } ); +#endif + } + if (SanitizerOptions->SanitizeHWAddress) { +#if LLVM_VERSION_GE(11, 0) + OptimizerLastEPCallbacks.push_back( + [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + MPM.addPass(HWAddressSanitizerPass( + /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover)); + } + ); +#else + PipelineStartEPCallbacks.push_back( + [SanitizerOptions](ModulePassManager &MPM) { + MPM.addPass(HWAddressSanitizerPass( + /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover)); + } + ); #endif } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 4118e93074563..45835990cecbb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::ReadNone; case InaccessibleMemOnly: return Attribute::InaccessibleMemOnly; + case SanitizeHWAddress: + return Attribute::SanitizeHWAddress; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 0467bf76afecc..98450f5a547da 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -540,7 +540,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - // Attempt to search similar mutable assosiated items for suggestion. + // Attempt to search similar mutable associated items for suggestion. // In the future, attempt in all path but initially for RHS of for_loop fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) { let hir = self.infcx.tcx.hir(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e9ea0ab6f98f5..210dbb0ee9939 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -43,6 +43,7 @@ bitflags! { const LEAK = 1 << 1; const MEMORY = 1 << 2; const THREAD = 1 << 3; + const HWADDRESS = 1 << 4; } } @@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet { SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::THREAD => "thread", + SanitizerSet::HWADDRESS => "hwaddress", _ => panic!("unrecognized sanitizer {:?}", s), }; if !first { @@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet { type IntoIter = std::vec::IntoIter<SanitizerSet>; fn into_iter(self) -> Self::IntoIter { - [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD] - .iter() - .copied() - .filter(|&s| self.contains(s)) - .collect::<Vec<_>>() - .into_iter() + [ + SanitizerSet::ADDRESS, + SanitizerSet::LEAK, + SanitizerSet::MEMORY, + SanitizerSet::THREAD, + SanitizerSet::HWADDRESS, + ] + .iter() + .copied() + .filter(|&s| self.contains(s)) + .collect::<Vec<_>>() + .into_iter() } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f78df8a7e29fa..baa0502521da7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -253,7 +253,7 @@ macro_rules! options { pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -476,6 +476,7 @@ macro_rules! options { "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "thread" => SanitizerSet::THREAD, + "hwaddress" => SanitizerSet::HWADDRESS, _ => return false, } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 69aa72d899fb3..a7ceb9e06a519 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1126,7 +1126,8 @@ impl Session { self.opts.optimize != config::OptLevel::No // AddressSanitizer uses lifetimes to detect use after scope bugs. // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY) + // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) } pub fn link_dead_code(&self) -> bool { @@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) { "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", ]; + const HWASAN_SUPPORTED_TARGETS: &[&str] = + &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; // Sanitizers can only be used on some tested platforms. for s in sess.opts.debugging_opts.sanitizer { @@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS, SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS, SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS, + SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS, _ => panic!("unrecognized sanitizer {}", s), }; if !supported_targets.contains(&&*sess.opts.target_triple.triple()) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 20e4f7262acb9..1c37a6b2aca18 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -593,6 +593,7 @@ symbols! { html_no_source, html_playground_url, html_root_url, + hwaddress, i, i128, i128_type, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e5045f906df59..2598f3e38ce00 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -280,7 +280,7 @@ impl ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id } } - pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> { + pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { AstConv::ast_ty_to_ty(self, ast_ty) } @@ -2709,10 +2709,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; } else if item.has_name(sym::thread) { codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; + } else if item.has_name(sym::hwaddress) { + codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS; } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `memory` or `thread`") + .note("expected one of: `address`, `hwaddress`, `memory` or `thread`") .emit(); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index e4eabca9c3b76..7fa58dcd5f44f 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -29,6 +29,73 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let parent_node = tcx.hir().get(parent_node_id); match parent_node { + // This match arm is for when the def_id appears in a GAT whose + // path can't be resolved without typechecking e.g. + // + // trait Foo { + // type Assoc<const N: usize>; + // fn foo() -> Self::Assoc<3>; + // } + // + // In the above code we would call this query with the def_id of 3 and + // the parent_node we match on would be the hir node for Self::Assoc<3> + // + // `Self::Assoc<3>` cant be resolved without typchecking here as we + // didnt write <Self as Foo>::Assoc<3>. If we did then another match + // arm would handle this. + // + // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU + Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + // Find the Item containing the associated type so we can create an ItemCtxt. + // Using the ItemCtxt convert the HIR for the unresolved assoc type into a + // ty which is a fully resolved projection. + // For the code example above, this would mean converting Self::Assoc<3> + // into a ty::Projection(<Self as Foo>::Assoc<3>) + let item_hir_id = tcx + .hir() + .parent_iter(hir_id) + .filter(|(_, node)| matches!(node, Node::Item(_))) + .map(|(id, _)| id) + .next() + .unwrap(); + let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id(); + let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; + let ty = item_ctxt.ast_ty_to_ty(hir_ty); + + // Iterate through the generics of the projection to find the one that corresponds to + // the def_id that this query was called with. We filter to only const args here as a + // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't + // but it can't hurt to be safe ^^ + if let ty::Projection(projection) = ty.kind() { + let generics = tcx.generics_of(projection.item_def_id); + + let arg_index = segment + .args + .and_then(|args| { + args.args + .iter() + .filter(|arg| arg.is_const()) + .position(|arg| arg.id() == hir_id) + }) + .unwrap_or_else(|| { + bug!("no arg matching AnonConst in segment"); + }); + + return generics + .params + .iter() + .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const)) + .nth(arg_index) + .map(|param| param.def_id); + } + + // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "unexpected non-GAT usage of an anon const", + ); + return None; + } Node::Expr(&Expr { kind: ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)), diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index fd44bafab6f76..22d95b8bcc08f 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -56,6 +56,7 @@ This API is completely unstable and subject to change. */ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -421,8 +422,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id); let env_def_id = tcx.hir().local_def_id(env_node_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); - - astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty) + item_cx.to_ty(hir_ty) } pub fn hir_trait_to_predicates<'tcx>( diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 885422732e401..cb772458e50b6 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1622,7 +1622,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { /// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the /// wrapped type. Types with an `UnsafeCell<T>` field are considered to have an 'unsafe interior'. /// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered -/// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior. +/// mutable. In general, transmuting a `&T` type into a `&mut T` is considered undefined behavior. /// /// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are /// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 98b8dca961407..9f98353452006 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -198,12 +198,13 @@ where Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) } } else if A::may_have_side_effect() && self.index < self.a.size() { + let i = self.index; + self.index += 1; // match the base implementation's potential side effects - // SAFETY: we just checked that `self.index` < `self.a.len()` + // SAFETY: we just checked that `i` < `self.a.len()` unsafe { - self.a.__iterator_get_unchecked(self.index); + self.a.__iterator_get_unchecked(i); } - self.index += 1; None } else { None diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c9c8f68cd9cce..5bb3f6bdcfd7b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -76,6 +76,10 @@ pub struct OsString { inner: Buf, } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for OsString {} + /// Borrowed reference to an OS string (see [`OsString`]). /// /// This type represents a borrowed reference to a string in the operating system's preferred @@ -100,6 +104,10 @@ pub struct OsStr { inner: Slice, } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for OsStr {} + impl OsString { /// Constructs a new empty `OsString`. /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 961cff661e3ba..d5e00ae4be659 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -582,3 +582,11 @@ include!("keyword_docs.rs"); // is unconditional, so the unstable feature needs to be defined somewhere. #[unstable(feature = "restricted_std", issue = "none")] mod __restricted_std_workaround {} + +mod sealed { + /// This trait being unreachable from outside the crate + /// prevents outside implementations of our extension traits. + /// This allows adding more trait methods in the future. + #[unstable(feature = "sealed", issue = "none")] + pub trait Sealed {} +} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index fb78e62834a07..6480e654c55f0 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -498,6 +498,10 @@ pub struct Command { inner: imp::Command, } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for Command {} + impl Command { /// Constructs a new `Command` for launching the program at /// path `program`, with the following default configuration: @@ -1375,6 +1379,10 @@ impl From<fs::File> for Stdio { #[stable(feature = "process", since = "1.0.0")] pub struct ExitStatus(imp::ExitStatus); +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for ExitStatus {} + impl ExitStatus { /// Was termination successful? Signal termination is not considered a /// success, and success is defined as a zero exit status. diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 724b5dcca6a36..7559c1f1d9e29 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -6,20 +6,16 @@ use crate::ffi::OsStr; use crate::io; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::process; +use crate::sealed::Sealed; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -mod private { - /// This trait being unreachable from outside the crate - /// prevents other implementations of the `ExitStatusExt` trait, - /// which allows potentially adding more trait methods in the future. - #[stable(feature = "none", since = "1.51.0")] - pub trait Sealed {} -} - /// Unix-specific extensions to the [`process::Command`] builder. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { +pub trait CommandExt: Sealed { /// Sets the child process's user ID. This translates to a /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. @@ -193,7 +189,7 @@ impl CommandExt for process::Command { /// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt: private::Sealed { +pub trait ExitStatusExt: Sealed { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] @@ -228,9 +224,6 @@ pub trait ExitStatusExt: private::Sealed { fn into_raw(self) -> i32; } -#[stable(feature = "none", since = "1.51.0")] -impl private::Sealed for process::ExitStatus {} - #[stable(feature = "rust1", since = "1.0.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: i32) -> Self { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index d5e14bec76572..1d1118aa69434 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -22,6 +22,7 @@ use crate::str; use crate::sys::cvt; use crate::sys::fd; use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; +use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -490,20 +491,20 @@ pub unsafe fn environ() -> *mut *const *const c_char { extern "C" { static mut environ: *const *const c_char; } - &mut environ + ptr::addr_of_mut!(environ) } -pub unsafe fn env_lock() -> StaticMutexGuard { - // It is UB to attempt to acquire this mutex reentrantly! - static ENV_LOCK: StaticMutex = StaticMutex::new(); - ENV_LOCK.lock() +static ENV_LOCK: StaticRWLock = StaticRWLock::new(); + +pub fn env_read_lock() -> RWLockReadGuard { + ENV_LOCK.read_with_guard() } /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { unsafe { - let _guard = env_lock(); + let _guard = env_read_lock(); let mut environ = *environ(); let mut result = Vec::new(); if !environ.is_null() { @@ -540,7 +541,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - let _guard = env_lock(); + let _guard = env_read_lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None @@ -556,7 +557,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - let _guard = env_lock(); + let _guard = ENV_LOCK.write_with_guard(); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) } } @@ -565,7 +566,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - let _guard = env_lock(); + let _guard = ENV_LOCK.write_with_guard(); cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) } } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 2746f87468dca..9e82df7755e89 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -47,7 +47,7 @@ impl Command { // a lock any more because the parent won't do anything and the child is // in its own process. let result = unsafe { - let _env_lock = sys::os::env_lock(); + let _env_lock = sys::os::env_read_lock(); cvt(libc::fork())? }; @@ -124,7 +124,7 @@ impl Command { // Similar to when forking, we want to ensure that access to // the environment is synchronized, so make sure to grab the // environment lock before we try to exec. - let _lock = sys::os::env_lock(); + let _lock = sys::os::env_read_lock(); let Err(e) = self.do_exec(theirs, envp.as_ref()); e @@ -404,7 +404,7 @@ impl Command { cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource - let _env_lock = sys::os::env_lock(); + let _env_lock = sys::os::env_read_lock(); let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); cvt_nz(libc::posix_spawnp( &mut p.pid, diff --git a/library/std/src/sys/windows/ext/ffi.rs b/library/std/src/sys/windows/ext/ffi.rs index 1df2a0df143b3..c89b9ff1efa6b 100644 --- a/library/std/src/sys/windows/ext/ffi.rs +++ b/library/std/src/sys/windows/ext/ffi.rs @@ -53,6 +53,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ffi::{OsStr, OsString}; +use crate::sealed::Sealed; use crate::sys::os_str::Buf; use crate::sys_common::wtf8::Wtf8Buf; use crate::sys_common::{AsInner, FromInner}; @@ -61,8 +62,11 @@ use crate::sys_common::{AsInner, FromInner}; pub use crate::sys_common::wtf8::EncodeWide; /// Windows-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { +pub trait OsStringExt: Sealed { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// @@ -92,8 +96,11 @@ impl OsStringExt for OsString { } /// Windows-specific extensions to [`OsStr`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { +pub trait OsStrExt: Sealed { /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially /// ill-formed UTF-16. /// diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 7a92381d6609b..3d680a7f2d94f 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -4,17 +4,10 @@ use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::process; +use crate::sealed::Sealed; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -mod private { - /// This trait being unreachable from outside the crate - /// prevents other implementations of the `ExitStatusExt` trait, - /// which allows potentially adding more trait methods in the future. - #[stable(feature = "none", since = "1.51.0")] - pub trait Sealed {} -} - #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { @@ -85,7 +78,7 @@ impl IntoRawHandle for process::ChildStderr { /// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "exit_status_from", since = "1.12.0")] -pub trait ExitStatusExt: private::Sealed { +pub trait ExitStatusExt: Sealed { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] @@ -99,12 +92,12 @@ impl ExitStatusExt for process::ExitStatus { } } -#[stable(feature = "none", since = "1.51.0")] -impl private::Sealed for process::ExitStatus {} - /// Windows-specific extensions to the [`process::Command`] builder. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "windows_process_extensions", since = "1.16.0")] -pub trait CommandExt { +pub trait CommandExt: Sealed { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs index 497e5fc7bdd16..302c519740717 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys_common/os_str_bytes.rs @@ -6,6 +6,7 @@ use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::mem; use crate::rc::Rc; +use crate::sealed::Sealed; use crate::str; use crate::sync::Arc; use crate::sys_common::bytestring::debug_fmt_bytestring; @@ -232,8 +233,11 @@ impl Slice { } /// Platform-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { +pub trait OsStringExt: Sealed { /// Creates an [`OsString`] from a byte vector. /// /// See the module documentation for an example. @@ -258,8 +262,11 @@ impl OsStringExt for OsString { } /// Platform-specific extensions to [`OsStr`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { +pub trait OsStrExt: Sealed { #[stable(feature = "rust1", since = "1.0.0")] /// Creates an [`OsStr`] from a byte slice. /// diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 3705d641a1be6..41e8ad7729463 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -86,3 +86,62 @@ impl RWLock { self.0.destroy() } } + +// the cfg annotations only exist due to dead code warnings. the code itself is portable +#[cfg(unix)] +pub struct StaticRWLock(RWLock); + +#[cfg(unix)] +impl StaticRWLock { + pub const fn new() -> StaticRWLock { + StaticRWLock(RWLock::new()) + } + + /// Acquires shared access to the underlying lock, blocking the current + /// thread to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn read_with_guard(&'static self) -> RWLockReadGuard { + // Safety: All methods require static references, therefore self + // cannot be moved between invocations. + unsafe { + self.0.read(); + } + RWLockReadGuard(&self.0) + } + + /// Acquires write access to the underlying lock, blocking the current thread + /// to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn write_with_guard(&'static self) -> RWLockWriteGuard { + // Safety: All methods require static references, therefore self + // cannot be moved between invocations. + unsafe { + self.0.write(); + } + RWLockWriteGuard(&self.0) + } +} + +#[cfg(unix)] +pub struct RWLockReadGuard(&'static RWLock); + +#[cfg(unix)] +impl Drop for RWLockReadGuard { + fn drop(&mut self) { + unsafe { self.0.read_unlock() } + } +} + +#[cfg(unix)] +pub struct RWLockWriteGuard(&'static RWLock); + +#[cfg(unix)] +impl Drop for RWLockWriteGuard { + fn drop(&mut self) { + unsafe { self.0.write_unlock() } + } +} diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 833c13e9a2615..dee0c15420136 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1075,8 +1075,11 @@ impl Step for Assemble { let src_exe = exe("llvm-dwp", target_compiler.host); let dst_exe = exe("rust-llvm-dwp", target_compiler.host); let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host }); - let llvm_bin_dir = llvm_config_bin.parent().unwrap(); - builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + if !builder.config.dry_run { + let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir")); + let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); + builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + } } // Ensure that `libLLVM.so` ends up in the newly build compiler directory, diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 2cabaee68ea67..2e6e9142afe6c 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -51,7 +51,7 @@ def v(*args): o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)") o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date") o("vendor", "build.vendor", "enable usage of vendored Rust crates") -o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)") +o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)") o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo") o("profiler", "build.profiler", "build the profiler runtime") diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index fd0acc3a919b0..22124ec67f5f3 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -29,7 +29,7 @@ fn install_sh( let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); let datadir = prefix.join(default_path(&builder.config.datadir, "share")); - let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc")); + let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust")); let mandir = prefix.join(default_path(&builder.config.mandir, "share/man")); let libdir = prefix.join(default_path(&builder.config.libdir, "lib")); let bindir = prefix.join(&builder.config.bindir); // Default in config.rs diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 609ac8b366952..b5a8b694c9420 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -804,7 +804,7 @@ fn supported_sanitizers( "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), "aarch64-unknown-linux-gnu" => { - common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"]) + common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"]) } "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]), diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index d03d5c7501424..4f7a101d2acbd 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -7,12 +7,15 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru This feature allows for use of one of following sanitizers: * [AddressSanitizer][clang-asan] a fast memory error detector. +* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to + AddressSanitizer, but based on partial hardware assistance. * [LeakSanitizer][clang-lsan] a run-time memory leak detector. * [MemorySanitizer][clang-msan] a detector of uninitialized reads. * [ThreadSanitizer][clang-tsan] a fast data race detector. -To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`, -`-Zsanitizer=memory` or `-Zsanitizer=thread`. +To enable a sanitizer compile with `-Zsanitizer=address`, +`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or +`-Zsanitizer=thread`. # AddressSanitizer @@ -174,6 +177,86 @@ Shadow byte legend (one shadow byte represents 8 application bytes): ==39249==ABORTING ``` +# HWAddressSanitizer + +HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much +less memory. + +HWAddressSanitizer is supported on the following targets: + +* `aarch64-linux-android` +* `aarch64-unknown-linux-gnu` + +HWAddressSanitizer requires `tagged-globals` target feature to instrument +globals. To enable this target feature compile with `-C +target-feature=+tagged-globals` + +## Example + +Heap buffer overflow: + +```rust +fn main() { + let xs = vec![0, 1, 2, 3]; + let _y = unsafe { *xs.as_ptr().offset(4) }; +} +``` + +```shell +$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C +linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target +aarch64-unknown-linux-gnu +``` + +```shell +$ ./main +==241==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdeffff0050 at pc 0xaaaae0ae4a98 +READ of size 4 at 0xefdeffff0050 tags: 2c/00 (ptr/mem) in thread T0 + #0 0xaaaae0ae4a94 (/.../main+0x54a94) + ... + +[0xefdeffff0040,0xefdeffff0060) is a small allocated heap chunk; size: 32 offset: 16 +0xefdeffff0050 is located 0 bytes to the right of 16-byte region [0xefdeffff0040,0xefdeffff0050) +allocated here: + #0 0xaaaae0acb80c (/.../main+0x3b80c) + ... + +Thread: T0 0xeffe00002000 stack: [0xffffc28ad000,0xffffc30ad000) sz: 8388608 tls: [0xffffaa10a020,0xffffaa10a7d0) +Memory tags around the buggy address (one tag corresponds to 16 bytes): + 0xfefcefffef80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffef90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffefa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffefb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffefc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffefd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffefe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefcefffeff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +=>0xfefceffff000: d7 d7 05 00 2c [00] 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0xfefceffff080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Tags for short granules around the buggy address (one tag corresponds to 16 bytes): + 0xfefcefffeff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. +=>0xfefceffff000: .. .. 8c .. .. [..] .. .. .. .. .. .. .. .. .. .. + 0xfefceffff010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. +See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags +Registers where the failure occurred (pc 0xaaaae0ae4a98): + x0 2c00efdeffff0050 x1 0000000000000004 x2 0000000000000004 x3 0000000000000000 + x4 0000fffefc30ac37 x5 000000000000005d x6 00000ffffc30ac37 x7 0000efff00000000 + x8 2c00efdeffff0050 x9 0200efff00000000 x10 0000000000000000 x11 0200efff00000000 + x12 0200effe00000310 x13 0200effe00000310 x14 0000000000000008 x15 5d00ffffc30ac360 + x16 0000aaaae0ad062c x17 0000000000000003 x18 0000000000000001 x19 0000ffffc30ac658 + x20 4e00ffffc30ac6e0 x21 0000aaaae0ac5e10 x22 0000000000000000 x23 0000000000000000 + x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000 + x28 0000000000000000 x29 0000ffffc30ac5a0 x30 0000aaaae0ae4a98 +SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94) +``` + # LeakSanitizer LeakSanitizer is run-time memory leak detector. @@ -321,11 +404,13 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT * [Sanitizers project page](https://github.com/google/sanitizers/wiki/) * [AddressSanitizer in Clang][clang-asan] +* [HWAddressSanitizer in Clang][clang-hwasan] * [LeakSanitizer in Clang][clang-lsan] * [MemorySanitizer in Clang][clang-msan] * [ThreadSanitizer in Clang][clang-tsan] [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html +[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 9c5ac1625afea..a50ed5b662bf6 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -89,35 +89,20 @@ function hasOwnProperty(obj, property) { return Object.prototype.hasOwnProperty.call(obj, property); } -function usableLocalStorage() { - // Check if the browser supports localStorage at all: - if (typeof Storage === "undefined") { - return false; - } - // Check if we can access it; this access will fail if the browser - // preferences deny access to localStorage, e.g., to prevent storage of - // "cookies" (or cookie-likes, as is the case here). - try { - return window.localStorage !== null && window.localStorage !== undefined; - } catch(err) { - // Storage is supported, but browser preferences deny access to it. - return false; - } -} - function updateLocalStorage(name, value) { - if (usableLocalStorage()) { - localStorage[name] = value; - } else { - // No Web Storage support so we do nothing + try { + window.localStorage.setItem(name, value); + } catch(e) { + // localStorage is not accessible, do nothing } } function getCurrentValue(name) { - if (usableLocalStorage() && localStorage[name] !== undefined) { - return localStorage[name]; + try { + return window.localStorage.getItem(name); + } catch(e) { + return null; } - return null; } function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs new file mode 100644 index 0000000000000..ab33ef6f2442c --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs @@ -0,0 +1,22 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Foo::Assoc GAT. + +trait Foo { + type Assoc<const N: usize>; + fn foo(&self) -> Self::Assoc<3>; +} + +impl Foo for () { + type Assoc<const N: usize> = [(); N]; + fn foo(&self) -> Self::Assoc<3> { + [(); 3] + } +} + +fn main() { + assert_eq!(().foo(), [(); 3]); +} diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs new file mode 100644 index 0000000000000..ba9a82ae72109 --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs @@ -0,0 +1,22 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Foo::Assoc GAT. + +trait Foo { + type Assoc<const N: usize>; + fn foo<const N: usize>(&self) -> Self::Assoc<N>; +} + +impl Foo for () { + type Assoc<const N: usize> = [(); N]; + fn foo<const N: usize>(&self) -> Self::Assoc<N> { + [(); N] + } +} + +fn main() { + assert_eq!(().foo::<10>(), [(); 10]); +} diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs new file mode 100644 index 0000000000000..9da5334056a37 --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs @@ -0,0 +1,27 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Bar::Assoc GAT. + +trait Bar { + type Assoc<const N: usize>; +} +trait Foo: Bar { + fn foo(&self) -> Self::Assoc<3>; +} + +impl Bar for () { + type Assoc<const N: usize> = [(); N]; +} + +impl Foo for () { + fn foo(&self) -> Self::Assoc<3> { + [(); 3] + } +} + +fn main() { + assert_eq!(().foo(), [(); 3]); +} diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr index e9983e5fbd24d..4c0b17c7d3769 100644 --- a/src/test/ui/invalid/invalid-no-sanitize.stderr +++ b/src/test/ui/invalid/invalid-no-sanitize.stderr @@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize` LL | #[no_sanitize(brontosaurus)] | ^^^^^^^^^^^^ | - = note: expected one of: `address`, `memory` or `thread` + = note: expected one of: `address`, `hwaddress`, `memory` or `thread` error: aborting due to previous error diff --git a/src/test/ui/sanitize/hwaddress.rs b/src/test/ui/sanitize/hwaddress.rs new file mode 100644 index 0000000000000..ad5d0245457ec --- /dev/null +++ b/src/test/ui/sanitize/hwaddress.rs @@ -0,0 +1,19 @@ +// needs-sanitizer-support +// needs-sanitizer-hwaddress +// +// compile-flags: -Z sanitizer=hwaddress -O -g +// +// run-fail +// error-pattern: HWAddressSanitizer: tag-mismatch + +#![feature(test)] + +use std::hint::black_box; + +fn main() { + let xs = vec![0, 1, 2, 3]; + // Avoid optimizing everything out. + let xs = black_box(xs.as_ptr()); + let code = unsafe { *xs.offset(4) }; + std::process::exit(code); +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 429a8c98cd57c..ff0d845be937c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -48,6 +48,7 @@ impl EarlyProps { let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); iter_header(testfile, None, rdr, &mut |ln| { // we should check if any only-<platform> exists and if it exists @@ -101,6 +102,10 @@ impl EarlyProps { props.ignore = true; } + if !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress") { + props.ignore = true; + } + if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) { props.ignore = true; } diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 292850bd9e277..b302953708c18 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-linux-gnu", ]; +pub const HWASAN_SUPPORTED_TARGETS: &[&str] = + &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; + const BIG_ENDIAN: &[&str] = &[ "aarch64_be", "armebv7r",