From 3d33af38b31bd885df502b7e9e6d0dd003ae900a Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Tue, 6 Dec 2022 18:12:46 +0100 Subject: Fix failing codegen tests on s390x Several codegen tests are currently failing due to making assumptions that are not valid for the s390x architecture: - catch-unwind.rs: fails due to inlining differences. Already ignored on another platform for the same reason. Solution: Ignore on s390x. - remap_path_prefix/main.rs: fails due to different alignment requirement for string constants. Solution: Do not test for the alignment requirement. - repr-transparent-aggregates-1.rs: many ABI assumptions. Already ignored on many platforms for the same reason. Solution: Ignore on s390x. - repr-transparent.rs: no vector ABI by default on s390x. Already ignored on another platform for a similar reason. Solution: Ignore on s390x. - uninit-consts.rs: hard-coded little-endian constant. Solution: Match both little- and big-endian versions. Fixes part of https://github.com/rust-lang/rust/issues/105383. --- src/test/codegen/catch-unwind.rs | 2 ++ src/test/codegen/remap_path_prefix/main.rs | 2 +- src/test/codegen/repr-transparent-aggregates-1.rs | 1 + src/test/codegen/repr-transparent.rs | 1 + src/test/codegen/uninit-consts.rs | 2 +- 5 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/catch-unwind.rs b/src/test/codegen/catch-unwind.rs index 3ea3a24bfae..b90ef104ce7 100644 --- a/src/test/codegen/catch-unwind.rs +++ b/src/test/codegen/catch-unwind.rs @@ -8,6 +8,8 @@ // On riscv the closure is another function, placed before fn foo so CHECK can't // find it // ignore-riscv64 FIXME +// On s390x the closure is also in another function +// ignore-s390x FIXME #![crate_type = "lib"] #![feature(c_unwind)] diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 9bef743ddcb..78ebbccfce1 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -12,7 +12,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 +// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 9d18c5f03c6..f733de12b35 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -8,6 +8,7 @@ // ignore-powerpc // ignore-powerpc64 // ignore-riscv64 see codegen/riscv-abi +// ignore-s390x // ignore-windows // See repr-transparent.rs diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index c68ba8460cb..4f2313ce47a 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -2,6 +2,7 @@ // ignore-riscv64 riscv64 has an i128 type used with test_Vector // see codegen/riscv-abi for riscv functiona call tests +// ignore-s390x s390x with default march passes vector types per reference #![crate_type="lib"] #![feature(repr_simd, transparent_unions)] diff --git a/src/test/codegen/uninit-consts.rs b/src/test/codegen/uninit-consts.rs index 4c07740b356..98a6761f8ab 100644 --- a/src/test/codegen/uninit-consts.rs +++ b/src/test/codegen/uninit-consts.rs @@ -14,7 +14,7 @@ pub struct PartiallyUninit { // CHECK: [[FULLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [10 x i8] }> undef -// CHECK: [[PARTIALLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"\EF\BE\AD\DE", [12 x i8] undef }>, align 4 +// CHECK: [[PARTIALLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4 // This shouldn't contain undef, since it contains more chunks // than the default value of uninit_const_chunk_threshold. -- cgit 1.4.1-3-g733a5 From 65698ae9f30f5ad72224edd1884fb4ddd1279366 Mon Sep 17 00:00:00 2001 From: Ramon de C Valle Date: Mon, 21 Nov 2022 21:29:00 -0800 Subject: Add LLVM KCFI support to the Rust compiler This commit adds LLVM Kernel Control Flow Integrity (KCFI) support to the Rust compiler. It initially provides forward-edge control flow protection for operating systems kernels for Rust-compiled code only by aggregating function pointers in groups identified by their return and parameter types. (See llvm/llvm-project@cff5bef.) Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space) will be provided in later work as part of this project by identifying C char and integer type uses at the time types are encoded (see Type metadata in the design document in the tracking issue #89653). LLVM KCFI can be enabled with -Zsanitizer=kcfi. Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- Cargo.lock | 12 ++++++ compiler/rustc_codegen_gcc/src/type_.rs | 4 ++ compiler/rustc_codegen_llvm/src/allocator.rs | 14 ++++-- compiler/rustc_codegen_llvm/src/builder.rs | 50 +++++++++++++++++++--- compiler/rustc_codegen_llvm/src/context.rs | 5 +++ compiler/rustc_codegen_llvm/src/declare.rs | 7 ++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +++- compiler/rustc_codegen_llvm/src/type_.rs | 15 +++++++ compiler/rustc_codegen_ssa/src/traits/type_.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 4 +- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 16 +++---- compiler/rustc_session/src/options.rs | 3 +- compiler/rustc_session/src/session.rs | 12 ++++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_symbol_mangling/Cargo.toml | 1 + compiler/rustc_symbol_mangling/src/typeid.rs | 24 +++++++++++ .../rustc_target/src/spec/aarch64_unknown_none.rs | 5 ++- compiler/rustc_target/src/spec/mod.rs | 6 ++- .../rustc_target/src/spec/x86_64_unknown_none.rs | 3 +- src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs | 11 +++++ ...cfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs | 47 ++++++++++++++++++++ src/test/ui/invalid/invalid-no-sanitize.stderr | 2 +- src/tools/compiletest/src/header.rs | 2 + src/tools/compiletest/src/util.rs | 2 + src/tools/tidy/src/deps.rs | 2 + 26 files changed, 231 insertions(+), 28 deletions(-) create mode 100644 src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs create mode 100644 src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs (limited to 'src/test/codegen') diff --git a/Cargo.lock b/Cargo.lock index fb6140e74fe..51108df4406 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4269,6 +4269,7 @@ dependencies = [ "rustc_span", "rustc_target", "tracing", + "twox-hash", ] [[package]] @@ -5197,6 +5198,17 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if 1.0.0", + "rand 0.8.5", + "static_assertions", +] + [[package]] name = "type-map" version = "0.4.0" diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index bdf7318ce48..89a415cdb36 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -300,4 +300,8 @@ impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // Unsupported. self.context.new_rvalue_from_int(self.int_type, 0) } + + fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) { + // Unsupported. + } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index fed56cdd438..668d9292705 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -88,7 +88,8 @@ pub(crate) unsafe fn codegen( callee, args.as_ptr(), args.len() as c_uint, - None, + [].as_ptr(), + 0 as c_uint, ); llvm::LLVMSetTailCall(ret, True); if output.is_some() { @@ -132,8 +133,15 @@ pub(crate) unsafe fn codegen( .enumerate() .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) .collect::>(); - let ret = - llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None); + let ret = llvm::LLVMRustBuildCall( + llbuilder, + ty, + callee, + args.as_ptr(), + args.len() as c_uint, + [].as_ptr(), + 0 as c_uint, + ); llvm::LLVMSetTailCall(ret, True); llvm::LLVMBuildRetVoid(llbuilder); llvm::LLVMDisposeBuilder(llbuilder); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 77dd15ef4d8..83bffb20e0c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; +use rustc_symbol_mangling::typeid::kcfi_typeid_for_fnabi; use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; @@ -225,9 +226,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { debug!("invoke {:?} with args ({:?})", llfn, args); let args = self.check_call("invoke", llty, llfn, args); - let bundle = funclet.map(|funclet| funclet.bundle()); - let bundle = bundle.as_ref().map(|b| &*b.raw); + let funclet_bundle = funclet.map(|funclet| funclet.bundle()); + let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); + let mut bundles = vec![funclet_bundle]; + + // Set KCFI operand bundle + let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() }; + let kcfi_bundle = + if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call { + let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap()); + Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + } else { + None + }; + if kcfi_bundle.is_some() { + let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); + bundles.push(kcfi_bundle); + } + bundles.retain(|bundle| bundle.is_some()); let invoke = unsafe { llvm::LLVMRustBuildInvoke( self.llbuilder, @@ -237,7 +254,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { args.len() as c_uint, then, catch, - bundle, + bundles.as_ptr(), + bundles.len() as c_uint, UNNAMED, ) }; @@ -1143,7 +1161,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { llfn, args.as_ptr() as *const &llvm::Value, args.len() as c_uint, - None, + [].as_ptr(), + 0 as c_uint, ); } } @@ -1159,9 +1178,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { debug!("call {:?} with args ({:?})", llfn, args); let args = self.check_call("call", llty, llfn, args); - let bundle = funclet.map(|funclet| funclet.bundle()); - let bundle = bundle.as_ref().map(|b| &*b.raw); + let funclet_bundle = funclet.map(|funclet| funclet.bundle()); + let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); + let mut bundles = vec![funclet_bundle]; + + // Set KCFI operand bundle + let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() }; + let kcfi_bundle = + if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call { + let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap()); + Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + } else { + None + }; + if kcfi_bundle.is_some() { + let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); + bundles.push(kcfi_bundle); + } + bundles.retain(|bundle| bundle.is_some()); let call = unsafe { llvm::LLVMRustBuildCall( self.llbuilder, @@ -1169,7 +1204,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { llfn, args.as_ptr() as *const &llvm::Value, args.len() as c_uint, - bundle, + bundles.as_ptr(), + bundles.len() as c_uint, ) }; if let Some(fn_abi) = fn_abi { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4dcc7cd5447..aa1735f38ac 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -250,6 +250,11 @@ pub unsafe fn create_module<'ll>( ); } + if sess.is_sanitizer_kcfi_enabled() { + let kcfi = "kcfi\0".as_ptr().cast(); + llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + } + // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { match sess.opts.cg.control_flow_guard { diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index dc21a02cec4..6a575095f7e 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -20,7 +20,7 @@ use crate::type_::Type; use crate::value::Value; use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_middle::ty::Ty; -use rustc_symbol_mangling::typeid::typeid_for_fnabi; +use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi}; use smallvec::SmallVec; /// Declare a function. @@ -136,6 +136,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.set_type_metadata(llfn, typeid); } + if self.tcx.sess.is_sanitizer_kcfi_enabled() { + let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi); + self.set_kcfi_type_metadata(llfn, kcfi_typeid); + } + llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index f4519849730..9bcc39cc760 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -427,6 +427,7 @@ pub enum MetadataType { MD_type = 19, MD_vcall_visibility = 28, MD_noundef = 29, + MD_kcfi_type = 36, } /// LLVMRustAsmDialect @@ -1060,6 +1061,7 @@ extern "C" { pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; + pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>; // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; @@ -1270,7 +1272,8 @@ extern "C" { NumArgs: c_uint, Then: &'a BasicBlock, Catch: &'a BasicBlock, - Bundle: Option<&OperandBundleDef<'a>>, + OpBundles: *const Option<&OperandBundleDef<'a>>, + NumOpBundles: c_uint, Name: *const c_char, ) -> &'a Value; pub fn LLVMBuildLandingPad<'a>( @@ -1640,7 +1643,8 @@ extern "C" { Fn: &'a Value, Args: *const &'a Value, NumArgs: c_uint, - Bundle: Option<&OperandBundleDef<'a>>, + OpBundles: *const Option<&OperandBundleDef<'a>>, + NumOpBundles: c_uint, ) -> &'a Value; pub fn LLVMRustBuildMemCpy<'a>( B: &Builder<'a>, diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5eec7dc6130..a5fab3479e7 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -316,4 +316,19 @@ impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) } } + + fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { + let kcfi_type_metadata = self.const_u32(kcfi_typeid); + unsafe { + llvm::LLVMGlobalSetMetadata( + function, + llvm::MD_kcfi_type as c_uint, + llvm::LLVMMDNodeInContext2( + self.llcx, + &llvm::LLVMValueAsMetadata(kcfi_type_metadata), + 1, + ), + ) + } + } } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 86481d5d758..109161ccc83 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -122,6 +122,7 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { fn set_type_metadata(&self, function: Self::Function, typeid: String); fn typeid_metadata(&self, typeid: String) -> Self::Value; + fn set_kcfi_type_metadata(&self, function: Self::Function, typeid: u32); } pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 4b6e068db43..6d8e78a0f18 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -394,7 +394,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding), gated!( no_sanitize, Normal, - template!(List: "address, memory, thread"), DuplicatesOk, + template!(List: "address, kcfi, memory, thread"), DuplicatesOk, experimental!(no_sanitize) ), gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a738ee4a148..7dce80de561 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1859,6 +1859,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS; } else if item.has_name(sym::cfi) { codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI; + } else if item.has_name(sym::kcfi) { + codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI; } else if item.has_name(sym::memory) { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; } else if item.has_name(sym::memtag) { @@ -1872,7 +1874,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") .emit(); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 216c35d6da0..49d028009fa 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1460,13 +1460,13 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef *Bundle) { + OperandBundleDef **OpBundles, + unsigned NumOpBundles) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); - unsigned Len = Bundle ? 1 : 0; - ArrayRef Bundles = makeArrayRef(Bundle, Len); return wrap(unwrap(B)->CreateCall( - FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles)); + FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), + makeArrayRef(*OpBundles, NumOpBundles))); } extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { @@ -1506,14 +1506,14 @@ extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef *Bundle, const char *Name) { + OperandBundleDef **OpBundles, unsigned NumOpBundles, + const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); - unsigned Len = Bundle ? 1 : 0; - ArrayRef Bundles = makeArrayRef(Bundle, Len); return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), makeArrayRef(unwrap(Args), NumArgs), - Bundles, Name)); + makeArrayRef(*OpBundles, NumOpBundles), + Name)); } extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f9ee202466f..088e9be28d3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -368,7 +368,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` 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`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory`, `memtag`, `shadow-call-stack`, 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`"; @@ -675,6 +675,7 @@ mod parse { *slot |= match s { "address" => SanitizerSet::ADDRESS, "cfi" => SanitizerSet::CFI, + "kcfi" => SanitizerSet::KCFI, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d602acec53e..f13f42cdf75 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -683,6 +683,10 @@ impl Session { self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } + pub fn is_sanitizer_kcfi_enabled(&self) -> bool { + self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI) + } + /// Check whether this compile session and crate type use static crt. pub fn crt_static(&self, crate_type: Option) -> bool { if !self.target.crt_static_respected { @@ -1530,6 +1534,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + // LLVM CFI and KCFI are mutually exclusive + if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() { + sess.emit_err(CannotMixAndMatchSanitizers { + first: "cfi".to_string(), + second: "kcfi".to_string(), + }); + } + if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { sess.emit_warning(StackProtectorNotSupportedForTarget { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 29312a21b4d..55eae88caf4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -828,6 +828,7 @@ symbols! { item_like_imports, iter, iter_repeat, + kcfi, keyword, kind, kreg, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 2a29ad6a9e5..4e447eab02e 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -10,6 +10,7 @@ bitflags = "1.2.1" tracing = "0.1" punycode = "0.4.0" rustc-demangle = "0.1.21" +twox-hash = "1.6.3" rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index 9228bea43f9..53983bed718 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -3,6 +3,8 @@ use rustc_middle::ty::{FnSig, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; +use std::hash::Hasher; +use twox_hash::XxHash64; mod typeid_itanium_cxx_abi; use typeid_itanium_cxx_abi::TypeIdOptions; @@ -16,3 +18,25 @@ pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String { typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS) } + +/// Returns an LLVM KCFI type metadata identifier for the specified FnAbi. +pub fn kcfi_typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> u32 { + // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half + // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write( + typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS).as_bytes(), + ); + hash.finish() as u32 +} + +/// Returns an LLVM KCFI type metadata identifier for the specified FnSig. +pub fn kcfi_typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> u32 { + // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half + // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write( + typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS).as_bytes(), + ); + hash.finish() as u32 +} diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index 4ae6d4120c9..aca52e1478e 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -6,13 +6,16 @@ // // For example, `-C target-cpu=cortex-a53`. -use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; +use super::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target, TargetOptions, +}; pub fn target() -> Target { let opts = TargetOptions { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), features: "+strict-align,+neon,+fp-armv8".into(), + supported_sanitizers: SanitizerSet::KCFI, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6d936d2cb9f..65ab7b953a1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -803,7 +803,7 @@ impl ToJson for StackProbeType { bitflags::bitflags! { #[derive(Default, Encodable, Decodable)] - pub struct SanitizerSet: u8 { + pub struct SanitizerSet: u16 { const ADDRESS = 1 << 0; const LEAK = 1 << 1; const MEMORY = 1 << 2; @@ -812,6 +812,7 @@ bitflags::bitflags! { const CFI = 1 << 5; const MEMTAG = 1 << 6; const SHADOWCALLSTACK = 1 << 7; + const KCFI = 1 << 8; } } @@ -823,6 +824,7 @@ impl SanitizerSet { Some(match self { SanitizerSet::ADDRESS => "address", SanitizerSet::CFI => "cfi", + SanitizerSet::KCFI => "kcfi", SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", @@ -858,6 +860,7 @@ impl IntoIterator for SanitizerSet { [ SanitizerSet::ADDRESS, SanitizerSet::CFI, + SanitizerSet::KCFI, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::MEMTAG, @@ -2292,6 +2295,7 @@ impl Target { base.$key_name |= match s.as_str() { Some("address") => SanitizerSet::ADDRESS, Some("cfi") => SanitizerSet::CFI, + Some("kcfi") => SanitizerSet::KCFI, Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, Some("memtag") => SanitizerSet::MEMTAG, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index e4d33c2b8c6..32060c35c11 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -5,7 +5,7 @@ // features. use super::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy}; -use super::{RelroLevel, StackProbeType, Target, TargetOptions}; +use super::{RelroLevel, SanitizerSet, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let opts = TargetOptions { @@ -20,6 +20,7 @@ pub fn target() -> Target { features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .into(), + supported_sanitizers: SanitizerSet::KCFI, disable_redzone: true, panic_strategy: PanicStrategy::Abort, code_model: Some(CodeModel::Kernel), diff --git a/src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs b/src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs new file mode 100644 index 00000000000..c2eb852aec3 --- /dev/null +++ b/src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs @@ -0,0 +1,11 @@ +// Verifies that "kcfi" module flag is added. +// +// needs-sanitizer-kcfi +// compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi + +#![crate_type="lib"] + +pub fn foo() { +} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1} diff --git a/src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs new file mode 100644 index 00000000000..0afd9727517 --- /dev/null +++ b/src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs @@ -0,0 +1,47 @@ +// Verifies that KCFI type metadata for functions are emitted. +// +// revisions: aarch64 x86_64 +// [aarch64] compile-flags: --target aarch64-unknown-none +// [aarch64] needs-llvm-components: aarch64 +// [x86_64] compile-flags: --target x86_64-unknown-none +// [x86_64] needs-llvm-components: +// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi + +#![crate_type="lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="copy"] +trait Copy { } + +impl Copy for i32 {} + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // FIXME(rcvalle): Change to !kcfi_type when Rust is updated to LLVM 16 + // CHECK-SAME: {{.*}}! ![[TYPE1:[0-9]+]] + // CHECK: call i32 %f(i32 %arg){{.*}}[ "kcfi"(i32 -1666898348) ] + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // FIXME(rcvalle): Change to !kcfi_type when Rust is updated to LLVM 16 + // CHECK-SAME: {{.*}}! ![[TYPE2:[0-9]+]] + // CHECK: call i32 %f(i32 %arg1, i32 %arg2){{.*}}[ "kcfi"(i32 -1789026986) ] + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // FIXME(rcvalle): Change to !kcfi_type when Rust is updated to LLVM 16 + // CHECK-SAME: {{.*}}! ![[TYPE3:[0-9]+]] + // CHECK: call i32 %f(i32 %arg1, i32 %arg2, i32 %arg3){{.*}}[ "kcfi"(i32 1248878270) ] + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i32 653723426} +// CHECK: ![[TYPE2]] = !{i32 412174924} +// CHECK: ![[TYPE3]] = !{i32 -636668840} diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr index d328cafa00b..4600034952b 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`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread` + = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` error: aborting due to previous error diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0d9a629e179..eae9e80a397 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -906,6 +906,7 @@ pub fn make_test_description( let has_asm_support = config.has_asm_support(); let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); + let has_kcfi = util::KCFI_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_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); @@ -957,6 +958,7 @@ pub fn make_test_description( && config.parse_name_directive(ln, "needs-sanitizer-support"); ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); + ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"); ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index ec36f1e4fb7..ccba313ee35 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -42,6 +42,8 @@ pub const CFI_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-netbsd", ]; +pub const KCFI_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-none", "x86_64-linux-none"]; + pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ // FIXME: currently broken, see #88132 // "aarch64-apple-darwin", diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8155ec9dd27..36dec1d415f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -214,6 +214,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "snap", "stable_deref_trait", "stacker", + "static_assertions", "syn", "synstructure", "tempfile", @@ -234,6 +235,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "tracing-log", "tracing-subscriber", "tracing-tree", + "twox-hash", "type-map", "typenum", "unic-char-property", -- cgit 1.4.1-3-g733a5 From 34246f89e268bd3741e51d21253951e3ffd53d74 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 8 Dec 2022 19:06:27 -0500 Subject: Add test case for ub in generated LLVM IR --- src/test/codegen/issue-105386-ub-in-debuginfo.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/codegen/issue-105386-ub-in-debuginfo.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/issue-105386-ub-in-debuginfo.rs b/src/test/codegen/issue-105386-ub-in-debuginfo.rs new file mode 100644 index 00000000000..e30f373a793 --- /dev/null +++ b/src/test/codegen/issue-105386-ub-in-debuginfo.rs @@ -0,0 +1,22 @@ +// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes +// min-llvm-version: 15.0 # this test uses opaque pointer notation +#![feature(stmt_expr_attributes)] + +pub struct S([usize; 8]); + +#[no_mangle] +pub fn outer_function(x: S, y: S) -> usize { + (#[inline(always)]|| { + let _z = x; + y.0[0] + })() +} + +// Check that we do not attempt to load from the spilled arg before it is assigned to +// when generating debuginfo. +// CHECK-LABEL: @outer_function +// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]" +// CHECK: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]] +// CHECK: [[load:%.*]] = load ptr, ptr [[ptr_tmp]] +// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]]) +// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x -- cgit 1.4.1-3-g733a5 From 7253057887b6de77e6847844311da517d2ada1eb Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 7 Dec 2022 13:48:34 -0500 Subject: Don't generate pointer loads to spills unless necessary In order for LLVM to correctly generate debuginfo for msvc, we sometimes need to spill arguments to the stack and perform some direct & indirect offsets into the value. Previously, this code always performed those actions, even when not required as LLVM would clean it up during optimization. However, when MIR inlining is enabled, this can cause problems as the operations occur prior to the spilled value being initialized. To solve this, we first calculate the necessary offsets using just the type which is side-effect free and does not alter the LLVM IR. Then, if we are in a situation which requires us to generate the LLVM IR (and this situation only occurs for arguments, not local variables) then we perform the same calculation again, this time generating the appropriate LLVM IR as we go. --- compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 29 ++++++++++++++++++++-- src/test/codegen/issue-105386-ub-in-debuginfo.rs | 4 +-- src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs | 20 +++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs (limited to 'src/test/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 8935d42548f..b7982b633f5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -103,6 +103,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> } } +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> + for TyAndLayout<'tcx> +{ + fn deref(&self, bx: &mut Bx) -> Self { + bx.cx().layout_of( + self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, + ) + } + + fn layout(&self) -> TyAndLayout<'tcx> { + *self + } + + fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self { + self.field(bx.cx(), field.index()) + } + + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { + self.for_variant(bx.cx(), variant) + } +} + struct DebugInfoOffset { /// Offset from the `base` used to calculate the debuginfo offset. direct_offset: Size, @@ -340,8 +362,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Some(dbg_var) = var.dbg_var else { continue }; let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - let DebugInfoOffset { direct_offset, indirect_offsets, result: place } = - calculate_debuginfo_offset(bx, local, &var, base); + let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, local, &var, base.layout); // When targeting MSVC, create extra allocas for arguments instead of pointing multiple // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records @@ -359,6 +381,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); if should_create_individual_allocas { + let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = + calculate_debuginfo_offset(bx, local, &var, base); + // Create a variable which will be a pointer to the actual value let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, diff --git a/src/test/codegen/issue-105386-ub-in-debuginfo.rs b/src/test/codegen/issue-105386-ub-in-debuginfo.rs index e30f373a793..d54ac9e33bc 100644 --- a/src/test/codegen/issue-105386-ub-in-debuginfo.rs +++ b/src/test/codegen/issue-105386-ub-in-debuginfo.rs @@ -16,7 +16,7 @@ pub fn outer_function(x: S, y: S) -> usize { // when generating debuginfo. // CHECK-LABEL: @outer_function // CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]" -// CHECK: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]] -// CHECK: [[load:%.*]] = load ptr, ptr [[ptr_tmp]] +// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]] +// CHECK-NOT: [[load:%.*]] = load ptr, ptr // CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]]) // CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x diff --git a/src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs b/src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs new file mode 100644 index 00000000000..6c6eb5d4e86 --- /dev/null +++ b/src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs @@ -0,0 +1,20 @@ +// run-pass +// compile-flags: --edition 2021 -Copt-level=3 -Cdebuginfo=2 -Zmir-opt-level=3 + +fn main() { + TranslatorI.visit_pre(); +} + +impl TranslatorI { + fn visit_pre(self) { + Some(()) + .map(|_| self.flags()) + .unwrap_or_else(|| self.flags()); + } +} + +struct TranslatorI; + +impl TranslatorI { + fn flags(&self) {} +} -- cgit 1.4.1-3-g733a5