Auto merge of #82045 - Dylan-DPC:rollup-244l0sb, r=Dylan-DPC
Rollup of 10 pull requests Successful merges: - #79775 (Fix injected errors when running doctests on a crate named after a keyword) - #81012 (Stabilize the partition_point feature) - #81479 (Allow casting mut array ref to mut ptr) - #81506 (HWAddressSanitizer support) - #81741 (Increment `self.index` before calling `Iterator::self.a.__iterator_ge…) - #81850 (use RWlock when accessing os::env) - #81911 (GAT/const_generics: Allow with_opt_const_param to return GAT param def_id) - #82022 (Push a `char` instead of a `str` with len one into a String) - #82023 (Remove unnecessary lint allow attrs on example) - #82030 (Use `Iterator::all` instead of open-coding it) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
21cbbdc44d
39 changed files with 496 additions and 78 deletions
|
@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
|
||||||
if enabled.contains(SanitizerSet::THREAD) {
|
if enabled.contains(SanitizerSet::THREAD) {
|
||||||
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
|
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.
|
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
|
||||||
|
|
|
@ -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_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
||||||
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
||||||
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
|
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
|
||||||
|
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
|
||||||
|
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
|
||||||
if config.sanitizer.contains(SanitizerSet::THREAD) {
|
if config.sanitizer.contains(SanitizerSet::THREAD) {
|
||||||
passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
|
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(
|
pub(crate) fn link(
|
||||||
|
|
|
@ -131,6 +131,7 @@ pub enum Attribute {
|
||||||
ReturnsTwice = 25,
|
ReturnsTwice = 25,
|
||||||
ReadNone = 26,
|
ReadNone = 26,
|
||||||
InaccessibleMemOnly = 27,
|
InaccessibleMemOnly = 27,
|
||||||
|
SanitizeHWAddress = 28,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMIntPredicate
|
/// LLVMIntPredicate
|
||||||
|
@ -439,6 +440,8 @@ pub struct SanitizerOptions {
|
||||||
pub sanitize_memory_recover: bool,
|
pub sanitize_memory_recover: bool,
|
||||||
pub sanitize_memory_track_origins: c_int,
|
pub sanitize_memory_track_origins: c_int,
|
||||||
pub sanitize_thread: bool,
|
pub sanitize_thread: bool,
|
||||||
|
pub sanitize_hwaddress: bool,
|
||||||
|
pub sanitize_hwaddress_recover: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMRelocMode
|
/// LLVMRelocMode
|
||||||
|
@ -2128,6 +2131,7 @@ extern "C" {
|
||||||
Recover: bool,
|
Recover: bool,
|
||||||
) -> &'static mut Pass;
|
) -> &'static mut Pass;
|
||||||
pub fn LLVMRustCreateThreadSanitizerPass() -> &'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 LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
|
||||||
pub fn LLVMRustAddLastExtensionPasses(
|
pub fn LLVMRustAddLastExtensionPasses(
|
||||||
PMB: &PassManagerBuilder,
|
PMB: &PassManagerBuilder,
|
||||||
|
|
|
@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
|
||||||
if sanitizer.contains(SanitizerSet::THREAD) {
|
if sanitizer.contains(SanitizerSet::THREAD) {
|
||||||
link_sanitizer_runtime(sess, linker, "tsan");
|
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) {
|
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||||
|
|
|
@ -85,6 +85,7 @@ enum LLVMRustAttribute {
|
||||||
ReturnsTwice = 25,
|
ReturnsTwice = 25,
|
||||||
ReadNone = 26,
|
ReadNone = 26,
|
||||||
InaccessibleMemOnly = 27,
|
InaccessibleMemOnly = 27,
|
||||||
|
SanitizeHWAddress = 28,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct OpaqueRustString *RustStringRef;
|
typedef struct OpaqueRustString *RustStringRef;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "llvm/Support/TimeProfiler.h"
|
#include "llvm/Support/TimeProfiler.h"
|
||||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||||
|
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
|
||||||
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
|
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
|
||||||
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
|
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
|
||||||
|
|
||||||
|
@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
|
||||||
return wrap(createThreadSanitizerLegacyPassPass());
|
return wrap(createThreadSanitizerLegacyPassPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
|
||||||
|
const bool CompileKernel = false;
|
||||||
|
|
||||||
|
return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
|
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
|
||||||
assert(RustPass);
|
assert(RustPass);
|
||||||
Pass *Pass = unwrap(RustPass);
|
Pass *Pass = unwrap(RustPass);
|
||||||
|
@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
|
||||||
bool SanitizeMemoryRecover;
|
bool SanitizeMemoryRecover;
|
||||||
int SanitizeMemoryTrackOrigins;
|
int SanitizeMemoryTrackOrigins;
|
||||||
bool SanitizeThread;
|
bool SanitizeThread;
|
||||||
|
bool SanitizeHWAddress;
|
||||||
|
bool SanitizeHWAddressRecover;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
|
@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager(
|
||||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
|
/*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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
||||||
return Attribute::ReadNone;
|
return Attribute::ReadNone;
|
||||||
case InaccessibleMemOnly:
|
case InaccessibleMemOnly:
|
||||||
return Attribute::InaccessibleMemOnly;
|
return Attribute::InaccessibleMemOnly;
|
||||||
|
case SanitizeHWAddress:
|
||||||
|
return Attribute::SanitizeHWAddress;
|
||||||
}
|
}
|
||||||
report_fatal_error("bad AttributeKind");
|
report_fatal_error("bad AttributeKind");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2191,19 +2191,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
CastKind::Pointer(PointerCast::ArrayToPointer) => {
|
CastKind::Pointer(PointerCast::ArrayToPointer) => {
|
||||||
let ty_from = op.ty(body, tcx);
|
let ty_from = op.ty(body, tcx);
|
||||||
|
|
||||||
let opt_ty_elem = match ty_from.kind() {
|
let opt_ty_elem_mut = match ty_from.kind() {
|
||||||
ty::RawPtr(ty::TypeAndMut {
|
ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
|
||||||
mutbl: hir::Mutability::Not,
|
match array_ty.kind() {
|
||||||
ty: array_ty,
|
ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
|
||||||
}) => match array_ty.kind() {
|
_ => None,
|
||||||
ty::Array(ty_elem, _) => Some(ty_elem),
|
}
|
||||||
_ => None,
|
}
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_elem = match opt_ty_elem {
|
let (ty_elem, ty_mut) = match opt_ty_elem_mut {
|
||||||
Some(ty_elem) => ty_elem,
|
Some(ty_elem_mut) => ty_elem_mut,
|
||||||
None => {
|
None => {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
|
@ -2215,11 +2214,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_to = match ty.kind() {
|
let (ty_to, ty_to_mut) = match ty.kind() {
|
||||||
ty::RawPtr(ty::TypeAndMut {
|
ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
|
||||||
mutbl: hir::Mutability::Not,
|
(ty_to, *ty_to_mut)
|
||||||
ty: ty_to,
|
}
|
||||||
}) => ty_to,
|
|
||||||
_ => {
|
_ => {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
|
@ -2231,6 +2229,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not {
|
||||||
|
span_mirbug!(
|
||||||
|
self,
|
||||||
|
rvalue,
|
||||||
|
"ArrayToPointer cast from const {:?} to mut {:?}",
|
||||||
|
ty,
|
||||||
|
ty_to
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(terr) = self.sub_types(
|
if let Err(terr) = self.sub_types(
|
||||||
ty_elem,
|
ty_elem,
|
||||||
ty_to,
|
ty_to,
|
||||||
|
|
|
@ -43,6 +43,7 @@ bitflags! {
|
||||||
const LEAK = 1 << 1;
|
const LEAK = 1 << 1;
|
||||||
const MEMORY = 1 << 2;
|
const MEMORY = 1 << 2;
|
||||||
const THREAD = 1 << 3;
|
const THREAD = 1 << 3;
|
||||||
|
const HWADDRESS = 1 << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet {
|
||||||
SanitizerSet::LEAK => "leak",
|
SanitizerSet::LEAK => "leak",
|
||||||
SanitizerSet::MEMORY => "memory",
|
SanitizerSet::MEMORY => "memory",
|
||||||
SanitizerSet::THREAD => "thread",
|
SanitizerSet::THREAD => "thread",
|
||||||
|
SanitizerSet::HWADDRESS => "hwaddress",
|
||||||
_ => panic!("unrecognized sanitizer {:?}", s),
|
_ => panic!("unrecognized sanitizer {:?}", s),
|
||||||
};
|
};
|
||||||
if !first {
|
if !first {
|
||||||
|
@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet {
|
||||||
type IntoIter = std::vec::IntoIter<SanitizerSet>;
|
type IntoIter = std::vec::IntoIter<SanitizerSet>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
[SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
|
[
|
||||||
.iter()
|
SanitizerSet::ADDRESS,
|
||||||
.copied()
|
SanitizerSet::LEAK,
|
||||||
.filter(|&s| self.contains(s))
|
SanitizerSet::MEMORY,
|
||||||
.collect::<Vec<_>>()
|
SanitizerSet::THREAD,
|
||||||
.into_iter()
|
SanitizerSet::HWADDRESS,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|&s| self.contains(s))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ macro_rules! options {
|
||||||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
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_panic_strategy: &str = "either `unwind` or `abort`";
|
||||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
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_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||||
pub const parse_cfguard: &str =
|
pub const parse_cfguard: &str =
|
||||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||||
|
@ -476,6 +476,7 @@ macro_rules! options {
|
||||||
"leak" => SanitizerSet::LEAK,
|
"leak" => SanitizerSet::LEAK,
|
||||||
"memory" => SanitizerSet::MEMORY,
|
"memory" => SanitizerSet::MEMORY,
|
||||||
"thread" => SanitizerSet::THREAD,
|
"thread" => SanitizerSet::THREAD,
|
||||||
|
"hwaddress" => SanitizerSet::HWADDRESS,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1126,7 +1126,8 @@ impl Session {
|
||||||
self.opts.optimize != config::OptLevel::No
|
self.opts.optimize != config::OptLevel::No
|
||||||
// AddressSanitizer uses lifetimes to detect use after scope bugs.
|
// AddressSanitizer uses lifetimes to detect use after scope bugs.
|
||||||
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
|
// 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 {
|
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-freebsd",
|
||||||
"x86_64-unknown-linux-gnu",
|
"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.
|
// Sanitizers can only be used on some tested platforms.
|
||||||
for s in sess.opts.debugging_opts.sanitizer {
|
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::LEAK => LSAN_SUPPORTED_TARGETS,
|
||||||
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
|
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
|
||||||
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
|
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
|
||||||
|
SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
|
||||||
_ => panic!("unrecognized sanitizer {}", s),
|
_ => panic!("unrecognized sanitizer {}", s),
|
||||||
};
|
};
|
||||||
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
|
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
|
||||||
|
|
|
@ -593,6 +593,7 @@ symbols! {
|
||||||
html_no_source,
|
html_no_source,
|
||||||
html_playground_url,
|
html_playground_url,
|
||||||
html_root_url,
|
html_root_url,
|
||||||
|
hwaddress,
|
||||||
i,
|
i,
|
||||||
i128,
|
i128,
|
||||||
i128_type,
|
i128_type,
|
||||||
|
|
|
@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
m_expr: ty::TypeAndMut<'tcx>,
|
m_expr: ty::TypeAndMut<'tcx>,
|
||||||
m_cast: ty::TypeAndMut<'tcx>,
|
m_cast: ty::TypeAndMut<'tcx>,
|
||||||
) -> Result<CastKind, CastError> {
|
) -> Result<CastKind, CastError> {
|
||||||
// array-ptr-cast.
|
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
||||||
|
if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
|
||||||
if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not {
|
|
||||||
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
||||||
// Due to the limitations of LLVM global constants,
|
// Due to the limitations of LLVM global constants,
|
||||||
// region pointers end up pointing at copies of
|
// region pointers end up pointing at copies of
|
||||||
|
|
|
@ -1211,7 +1211,7 @@ fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
|
||||||
ProjectionKind::Subslice => String::from("Subslice"),
|
ProjectionKind::Subslice => String::from("Subslice"),
|
||||||
};
|
};
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
projections_str.push_str(",");
|
projections_str.push(',');
|
||||||
}
|
}
|
||||||
projections_str.push_str(proj.as_str());
|
projections_str.push_str(proj.as_str());
|
||||||
}
|
}
|
||||||
|
@ -1382,14 +1382,8 @@ fn determine_place_ancestry_relation(
|
||||||
// Assume of length of projections_b = m
|
// Assume of length of projections_b = m
|
||||||
let projections_b = &place_b.projections;
|
let projections_b = &place_b.projections;
|
||||||
|
|
||||||
let mut same_initial_projections = true;
|
let same_initial_projections =
|
||||||
|
projections_a.iter().zip(projections_b.iter()).all(|(proj_a, proj_b)| proj_a == proj_b);
|
||||||
for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) {
|
|
||||||
if proj_a != proj_b {
|
|
||||||
same_initial_projections = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if same_initial_projections {
|
if same_initial_projections {
|
||||||
// First min(n, m) projections are the same
|
// First min(n, m) projections are the same
|
||||||
|
|
|
@ -2709,10 +2709,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
||||||
} else if item.has_name(sym::thread) {
|
} else if item.has_name(sym::thread) {
|
||||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
||||||
|
} else if item.has_name(sym::hwaddress) {
|
||||||
|
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
|
||||||
} else {
|
} else {
|
||||||
tcx.sess
|
tcx.sess
|
||||||
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
.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();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
let parent_node = tcx.hir().get(parent_node_id);
|
||||||
|
|
||||||
match parent_node {
|
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 {
|
Node::Expr(&Expr {
|
||||||
kind:
|
kind:
|
||||||
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
|
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
|
||||||
|
|
|
@ -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/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
|
#![feature(bindings_after_at)]
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
|
|
|
@ -99,13 +99,11 @@
|
||||||
//! pub struct Foo;
|
//! pub struct Foo;
|
||||||
//!
|
//!
|
||||||
//! #[no_mangle]
|
//! #[no_mangle]
|
||||||
//! #[allow(improper_ctypes_definitions)]
|
|
||||||
//! pub extern "C" fn foo_new() -> Box<Foo> {
|
//! pub extern "C" fn foo_new() -> Box<Foo> {
|
||||||
//! Box::new(Foo)
|
//! Box::new(Foo)
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[no_mangle]
|
//! #[no_mangle]
|
||||||
//! #[allow(improper_ctypes_definitions)]
|
|
||||||
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
|
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -198,12 +198,13 @@ where
|
||||||
Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
|
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() {
|
} else if A::may_have_side_effect() && self.index < self.a.size() {
|
||||||
// match the base implementation's potential side effects
|
let i = self.index;
|
||||||
// SAFETY: we just checked that `self.index` < `self.a.len()`
|
|
||||||
unsafe {
|
|
||||||
self.a.__iterator_get_unchecked(self.index);
|
|
||||||
}
|
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
|
// match the base implementation's potential side effects
|
||||||
|
// SAFETY: we just checked that `i` < `self.a.len()`
|
||||||
|
unsafe {
|
||||||
|
self.a.__iterator_get_unchecked(i);
|
||||||
|
}
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -2082,6 +2082,12 @@ impl<T> [T] {
|
||||||
/// [`Result::Err`] is returned, containing the index where a matching
|
/// [`Result::Err`] is returned, containing the index where a matching
|
||||||
/// element could be inserted while maintaining sorted order.
|
/// element could be inserted while maintaining sorted order.
|
||||||
///
|
///
|
||||||
|
/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
|
||||||
|
///
|
||||||
|
/// [`binary_search_by`]: #method.binary_search_by
|
||||||
|
/// [`binary_search_by_key`]: #method.binary_search_by_key
|
||||||
|
/// [`partition_point`]: #method.partition_point
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Looks up a series of four elements. The first is found, with a
|
/// Looks up a series of four elements. The first is found, with a
|
||||||
|
@ -2129,6 +2135,12 @@ impl<T> [T] {
|
||||||
/// [`Result::Err`] is returned, containing the index where a matching
|
/// [`Result::Err`] is returned, containing the index where a matching
|
||||||
/// element could be inserted while maintaining sorted order.
|
/// element could be inserted while maintaining sorted order.
|
||||||
///
|
///
|
||||||
|
/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
|
||||||
|
///
|
||||||
|
/// [`binary_search`]: #method.binary_search
|
||||||
|
/// [`binary_search_by_key`]: #method.binary_search_by_key
|
||||||
|
/// [`partition_point`]: #method.partition_point
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Looks up a series of four elements. The first is found, with a
|
/// Looks up a series of four elements. The first is found, with a
|
||||||
|
@ -2186,7 +2198,12 @@ impl<T> [T] {
|
||||||
/// [`Result::Err`] is returned, containing the index where a matching
|
/// [`Result::Err`] is returned, containing the index where a matching
|
||||||
/// element could be inserted while maintaining sorted order.
|
/// element could be inserted while maintaining sorted order.
|
||||||
///
|
///
|
||||||
|
/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
|
||||||
|
///
|
||||||
/// [`sort_by_key`]: #method.sort_by_key
|
/// [`sort_by_key`]: #method.sort_by_key
|
||||||
|
/// [`binary_search`]: #method.binary_search
|
||||||
|
/// [`binary_search_by`]: #method.binary_search_by
|
||||||
|
/// [`partition_point`]: #method.partition_point
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -3399,11 +3416,15 @@ impl<T> [T] {
|
||||||
/// If this slice is not partitioned, the returned result is unspecified and meaningless,
|
/// If this slice is not partitioned, the returned result is unspecified and meaningless,
|
||||||
/// as this method performs a kind of binary search.
|
/// as this method performs a kind of binary search.
|
||||||
///
|
///
|
||||||
|
/// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`].
|
||||||
|
///
|
||||||
|
/// [`binary_search`]: #method.binary_search
|
||||||
|
/// [`binary_search_by`]: #method.binary_search_by
|
||||||
|
/// [`binary_search_by_key`]: #method.binary_search_by_key
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(partition_point)]
|
|
||||||
///
|
|
||||||
/// let v = [1, 2, 3, 3, 5, 6, 7];
|
/// let v = [1, 2, 3, 3, 5, 6, 7];
|
||||||
/// let i = v.partition_point(|&x| x < 5);
|
/// let i = v.partition_point(|&x| x < 5);
|
||||||
///
|
///
|
||||||
|
@ -3411,7 +3432,7 @@ impl<T> [T] {
|
||||||
/// assert!(v[..i].iter().all(|&x| x < 5));
|
/// assert!(v[..i].iter().all(|&x| x < 5));
|
||||||
/// assert!(v[i..].iter().all(|&x| !(x < 5)));
|
/// assert!(v[i..].iter().all(|&x| !(x < 5)));
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "partition_point", reason = "new API", issue = "73831")]
|
#[stable(feature = "partition_point", since = "1.52.0")]
|
||||||
pub fn partition_point<P>(&self, mut pred: P) -> usize
|
pub fn partition_point<P>(&self, mut pred: P) -> usize
|
||||||
where
|
where
|
||||||
P: FnMut(&T) -> bool,
|
P: FnMut(&T) -> bool,
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
#![feature(option_result_unwrap_unchecked)]
|
#![feature(option_result_unwrap_unchecked)]
|
||||||
#![feature(option_unwrap_none)]
|
#![feature(option_unwrap_none)]
|
||||||
#![feature(peekable_peek_mut)]
|
#![feature(peekable_peek_mut)]
|
||||||
#![feature(partition_point)]
|
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
#![feature(unsafe_block_in_unsafe_fn)]
|
#![feature(unsafe_block_in_unsafe_fn)]
|
||||||
#![feature(int_bits_const)]
|
#![feature(int_bits_const)]
|
||||||
|
|
|
@ -22,6 +22,7 @@ use crate::str;
|
||||||
use crate::sys::cvt;
|
use crate::sys::cvt;
|
||||||
use crate::sys::fd;
|
use crate::sys::fd;
|
||||||
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
|
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
|
||||||
|
use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock};
|
||||||
use crate::vec;
|
use crate::vec;
|
||||||
|
|
||||||
use libc::{c_char, c_int, c_void};
|
use libc::{c_char, c_int, c_void};
|
||||||
|
@ -490,20 +491,20 @@ pub unsafe fn environ() -> *mut *const *const c_char {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static mut environ: *const *const c_char;
|
static mut environ: *const *const c_char;
|
||||||
}
|
}
|
||||||
&mut environ
|
ptr::addr_of_mut!(environ)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn env_lock() -> StaticMutexGuard {
|
static ENV_LOCK: StaticRWLock = StaticRWLock::new();
|
||||||
// It is UB to attempt to acquire this mutex reentrantly!
|
|
||||||
static ENV_LOCK: StaticMutex = StaticMutex::new();
|
pub fn env_read_lock() -> RWLockReadGuard {
|
||||||
ENV_LOCK.lock()
|
ENV_LOCK.read_with_guard()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a vector of (variable, value) byte-vector pairs for all the
|
/// Returns a vector of (variable, value) byte-vector pairs for all the
|
||||||
/// environment variables of the current process.
|
/// environment variables of the current process.
|
||||||
pub fn env() -> Env {
|
pub fn env() -> Env {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _guard = env_lock();
|
let _guard = env_read_lock();
|
||||||
let mut environ = *environ();
|
let mut environ = *environ();
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
if !environ.is_null() {
|
if !environ.is_null() {
|
||||||
|
@ -540,7 +541,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
|
||||||
// always None as well
|
// always None as well
|
||||||
let k = CString::new(k.as_bytes())?;
|
let k = CString::new(k.as_bytes())?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _guard = env_lock();
|
let _guard = env_read_lock();
|
||||||
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
|
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
|
||||||
let ret = if s.is_null() {
|
let ret = if s.is_null() {
|
||||||
None
|
None
|
||||||
|
@ -556,7 +557,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
||||||
let v = CString::new(v.as_bytes())?;
|
let v = CString::new(v.as_bytes())?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _guard = env_lock();
|
let _guard = ENV_LOCK.write_with_guard();
|
||||||
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
|
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())?;
|
let nbuf = CString::new(n.as_bytes())?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _guard = env_lock();
|
let _guard = ENV_LOCK.write_with_guard();
|
||||||
cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
|
cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl Command {
|
||||||
// a lock any more because the parent won't do anything and the child is
|
// a lock any more because the parent won't do anything and the child is
|
||||||
// in its own process.
|
// in its own process.
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
let _env_lock = sys::os::env_lock();
|
let _env_lock = sys::os::env_read_lock();
|
||||||
cvt(libc::fork())?
|
cvt(libc::fork())?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ impl Command {
|
||||||
// Similar to when forking, we want to ensure that access to
|
// Similar to when forking, we want to ensure that access to
|
||||||
// the environment is synchronized, so make sure to grab the
|
// the environment is synchronized, so make sure to grab the
|
||||||
// environment lock before we try to exec.
|
// 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());
|
let Err(e) = self.do_exec(theirs, envp.as_ref());
|
||||||
e
|
e
|
||||||
|
@ -404,7 +404,7 @@ impl Command {
|
||||||
cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
|
cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
|
||||||
|
|
||||||
// Make sure we synchronize access to the global `environ` resource
|
// 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 _);
|
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||||
cvt_nz(libc::posix_spawnp(
|
cvt_nz(libc::posix_spawnp(
|
||||||
&mut p.pid,
|
&mut p.pid,
|
||||||
|
|
|
@ -86,3 +86,62 @@ impl RWLock {
|
||||||
self.0.destroy()
|
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() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ o("option-checking", None, "complain about unrecognized options in this configur
|
||||||
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
|
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("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
|
||||||
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
|
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("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("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
|
||||||
o("profiler", "build.profiler", "build the profiler runtime")
|
o("profiler", "build.profiler", "build the profiler runtime")
|
||||||
|
|
|
@ -804,7 +804,7 @@ fn supported_sanitizers(
|
||||||
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
|
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
|
||||||
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
|
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
|
||||||
"aarch64-unknown-linux-gnu" => {
|
"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-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
|
||||||
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
|
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
|
||||||
|
|
|
@ -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:
|
This feature allows for use of one of following sanitizers:
|
||||||
|
|
||||||
* [AddressSanitizer][clang-asan] a fast memory error detector.
|
* [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.
|
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
|
||||||
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
|
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
|
||||||
* [ThreadSanitizer][clang-tsan] a fast data race detector.
|
* [ThreadSanitizer][clang-tsan] a fast data race detector.
|
||||||
|
|
||||||
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
|
To enable a sanitizer compile with `-Zsanitizer=address`,
|
||||||
`-Zsanitizer=memory` or `-Zsanitizer=thread`.
|
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
|
||||||
|
`-Zsanitizer=thread`.
|
||||||
|
|
||||||
# AddressSanitizer
|
# AddressSanitizer
|
||||||
|
|
||||||
|
@ -174,6 +177,86 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
|
||||||
==39249==ABORTING
|
==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
|
||||||
|
|
||||||
LeakSanitizer is run-time memory leak detector.
|
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/)
|
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
|
||||||
* [AddressSanitizer in Clang][clang-asan]
|
* [AddressSanitizer in Clang][clang-asan]
|
||||||
|
* [HWAddressSanitizer in Clang][clang-hwasan]
|
||||||
* [LeakSanitizer in Clang][clang-lsan]
|
* [LeakSanitizer in Clang][clang-lsan]
|
||||||
* [MemorySanitizer in Clang][clang-msan]
|
* [MemorySanitizer in Clang][clang-msan]
|
||||||
* [ThreadSanitizer in Clang][clang-tsan]
|
* [ThreadSanitizer in Clang][clang-tsan]
|
||||||
|
|
||||||
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
|
[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-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
|
||||||
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
|
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
|
||||||
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
|
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
|
||||||
|
|
|
@ -546,9 +546,12 @@ crate fn make_test(
|
||||||
// compiler.
|
// compiler.
|
||||||
if !already_has_extern_crate && !opts.no_crate_inject && cratename != Some("std") {
|
if !already_has_extern_crate && !opts.no_crate_inject && cratename != Some("std") {
|
||||||
if let Some(cratename) = cratename {
|
if let Some(cratename) = cratename {
|
||||||
// Make sure its actually used if not included.
|
// Don't inject `extern crate` if the crate is never used.
|
||||||
|
// NOTE: this is terribly inaccurate because it doesn't actually
|
||||||
|
// parse the source, but only has false positives, not false
|
||||||
|
// negatives.
|
||||||
if s.contains(cratename) {
|
if s.contains(cratename) {
|
||||||
prog.push_str(&format!("extern crate {};\n", cratename));
|
prog.push_str(&format!("extern crate r#{};\n", cratename));
|
||||||
line_offset += 1;
|
line_offset += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn make_test_crate_name() {
|
||||||
let input = "use asdf::qwop;
|
let input = "use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);";
|
assert_eq!(2+2, 4);";
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![allow(unused)]
|
||||||
extern crate asdf;
|
extern crate r#asdf;
|
||||||
fn main() {
|
fn main() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);
|
assert_eq!(2+2, 4);
|
||||||
|
@ -128,7 +128,7 @@ fn make_test_opts_attrs() {
|
||||||
let input = "use asdf::qwop;
|
let input = "use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);";
|
assert_eq!(2+2, 4);";
|
||||||
let expected = "#![feature(sick_rad)]
|
let expected = "#![feature(sick_rad)]
|
||||||
extern crate asdf;
|
extern crate r#asdf;
|
||||||
fn main() {
|
fn main() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);
|
assert_eq!(2+2, 4);
|
||||||
|
@ -141,7 +141,7 @@ assert_eq!(2+2, 4);
|
||||||
opts.attrs.push("feature(hella_dope)".to_string());
|
opts.attrs.push("feature(hella_dope)".to_string());
|
||||||
let expected = "#![feature(sick_rad)]
|
let expected = "#![feature(sick_rad)]
|
||||||
#![feature(hella_dope)]
|
#![feature(hella_dope)]
|
||||||
extern crate asdf;
|
extern crate r#asdf;
|
||||||
fn main() {
|
fn main() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);
|
assert_eq!(2+2, 4);
|
||||||
|
@ -250,7 +250,7 @@ assert_eq!(asdf::foo, 4);";
|
||||||
|
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![allow(unused)]
|
||||||
extern crate hella_qwop;
|
extern crate hella_qwop;
|
||||||
extern crate asdf;
|
extern crate r#asdf;
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(asdf::foo, 4);
|
assert_eq!(asdf::foo, 4);
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -11,4 +11,4 @@
|
||||||
pub fn dummy() {}
|
pub fn dummy() {}
|
||||||
|
|
||||||
// ensure that `extern crate foo;` was inserted into code snips automatically:
|
// ensure that `extern crate foo;` was inserted into code snips automatically:
|
||||||
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
|
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Issue #14893. Tests that casts from vectors don't behave strangely in the
|
// Issue #14893. Tests that casts from vectors don't behave strangely in the
|
||||||
// presence of the `_` type shorthand notation.
|
// presence of the `_` type shorthand notation.
|
||||||
|
//
|
||||||
// Update: after a change to the way casts are done, we have more type information
|
// Update: after a change to the way casts are done, we have more type information
|
||||||
// around and so the errors here are no longer exactly the same.
|
// around and so the errors here are no longer exactly the same.
|
||||||
|
//
|
||||||
|
// Update: With PR #81479 some of the previously rejected cases are now allowed.
|
||||||
|
// New test cases added.
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
y: [u8; 2],
|
y: [u8; 2],
|
||||||
|
@ -12,13 +16,19 @@ fn main() {
|
||||||
|
|
||||||
// No longer a type mismatch - the `_` can be fully resolved by type inference.
|
// No longer a type mismatch - the `_` can be fully resolved by type inference.
|
||||||
let p1: *const u8 = &x1.y as *const _;
|
let p1: *const u8 = &x1.y as *const _;
|
||||||
|
let p1: *mut u8 = &x1.y as *mut _;
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut u8` is invalid
|
||||||
let t1: *const [u8; 2] = &x1.y as *const _;
|
let t1: *const [u8; 2] = &x1.y as *const _;
|
||||||
|
let t1: *mut [u8; 2] = &x1.y as *mut _;
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
|
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
|
||||||
|
let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
|
||||||
let mut x1 = X { y: [0, 0] };
|
let mut x1 = X { y: [0, 0] };
|
||||||
|
|
||||||
// This is still an error since we don't allow casts from &mut [T; n] to *mut T.
|
let p1: *mut u8 = &mut x1.y as *mut _;
|
||||||
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR casting
|
let p2: *const u8 = &mut x1.y as *const _;
|
||||||
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
|
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
|
||||||
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
|
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid
|
error[E0606]: casting `&[u8; 2]` as `*mut u8` is invalid
|
||||||
--> $DIR/vector-cast-weirdness.rs:21:23
|
--> $DIR/vector-cast-weirdness.rs:19:23
|
||||||
|
|
|
|
||||||
LL | let p1: *mut u8 = &mut x1.y as *mut _;
|
LL | let p1: *mut u8 = &x1.y as *mut _;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
--> $DIR/vector-cast-weirdness.rs:22:28
|
||||||
|
|
|
||||||
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut _;
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
--> $DIR/vector-cast-weirdness.rs:25:28
|
||||||
|
|
|
||||||
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0606`.
|
For more information about this error, try `rustc --explain E0606`.
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
|
||||||
LL | #[no_sanitize(brontosaurus)]
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
19
src/test/ui/sanitize/hwaddress.rs
Normal file
19
src/test/ui/sanitize/hwaddress.rs
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ impl EarlyProps {
|
||||||
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||||
let has_msan = util::MSAN_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_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| {
|
iter_header(testfile, None, rdr, &mut |ln| {
|
||||||
// we should check if any only-<platform> exists and if it exists
|
// we should check if any only-<platform> exists and if it exists
|
||||||
|
@ -101,6 +102,10 @@ impl EarlyProps {
|
||||||
props.ignore = true;
|
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) {
|
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
|
||||||
props.ignore = true;
|
props.ignore = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
|
||||||
"x86_64-unknown-linux-gnu",
|
"x86_64-unknown-linux-gnu",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
|
||||||
|
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
|
||||||
|
|
||||||
const BIG_ENDIAN: &[&str] = &[
|
const BIG_ENDIAN: &[&str] = &[
|
||||||
"aarch64_be",
|
"aarch64_be",
|
||||||
"armebv7r",
|
"armebv7r",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue