mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #105452 - rcvalle:rust-cfi-3, r=bjorn3
Add cross-language LLVM CFI support to the Rust compiler This PR adds cross-language LLVM Control Flow Integrity (CFI) support to the Rust compiler by adding the `-Zsanitizer-cfi-normalize-integers` option to be used with Clang `-fsanitize-cfi-icall-normalize-integers` for normalizing integer types (see https://reviews.llvm.org/D139395). It provides 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). For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, see design document in the tracking issue #89653. Cross-language LLVM CFI can be enabled with -Zsanitizer=cfi and -Zsanitizer-cfi-normalize-integers, and requires proper (i.e., non-rustc) LTO (i.e., -Clinker-plugin-lto). Thank you again, ``@bjorn3,`` ``@nikic,`` ``@samitolvanen,`` and the Rust community for all the help!
This commit is contained in:
commit
38bbc39895
@ -501,7 +501,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
if options.contains(InlineAsmOptions::NORETURN) {
|
||||
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
|
||||
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
|
||||
self.call(self.type_void(), None, builtin_unreachable, &[], None);
|
||||
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
|
||||
}
|
||||
|
||||
// Write results to outputs.
|
||||
|
@ -35,6 +35,7 @@ use rustc_codegen_ssa::traits::{
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_span::Span;
|
||||
@ -455,12 +456,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
fn invoke(&mut self, typ: Type<'gcc>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
let try_block = self.current_func().new_block("try");
|
||||
|
||||
let current_block = self.block.clone();
|
||||
self.block = try_block;
|
||||
let call = self.call(typ, None, func, args, None); // TODO(antoyo): use funclet here?
|
||||
let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here?
|
||||
self.block = current_block;
|
||||
|
||||
let return_value = self.current_func()
|
||||
@ -483,8 +484,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
fn invoke(&mut self, typ: Type<'gcc>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
let call_site = self.call(typ, None, func, args, None);
|
||||
fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
let call_site = self.call(typ, fn_attrs, None, func, args, None);
|
||||
let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
|
||||
self.llbb().end_with_conditional(None, condition, then, catch);
|
||||
if let Some(_fn_abi) = fn_abi {
|
||||
@ -1351,6 +1352,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn call(
|
||||
&mut self,
|
||||
_typ: Type<'gcc>,
|
||||
_fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
func: RValue<'gcc>,
|
||||
args: &[RValue<'gcc>],
|
||||
|
@ -113,7 +113,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
_ if simple.is_some() => {
|
||||
// FIXME(antoyo): remove this cast when the API supports function.
|
||||
let func = unsafe { std::mem::transmute(simple.expect("simple")) };
|
||||
self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
|
||||
self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
|
||||
},
|
||||
sym::likely => {
|
||||
self.expect(args[0].immediate(), true)
|
||||
@ -326,7 +326,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
let masked = self.and(addr, mask);
|
||||
self.bitcast(masked, void_ptr_type)
|
||||
},
|
||||
|
||||
|
||||
_ if name_str.starts_with("simd_") => {
|
||||
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
|
||||
Ok(llval) => llval,
|
||||
@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn abort(&mut self) {
|
||||
let func = self.context.get_builtin_function("abort");
|
||||
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
|
||||
self.call(self.type_void(), None, func, &[], None);
|
||||
self.call(self.type_void(), None, None, func, &[], None);
|
||||
}
|
||||
|
||||
fn assume(&mut self, value: Self::Value) {
|
||||
@ -1135,7 +1135,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
||||
|
||||
fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
|
||||
if bx.sess().panic_strategy() == PanicStrategy::Abort {
|
||||
bx.call(bx.type_void(), None, try_func, &[data], None);
|
||||
bx.call(bx.type_void(), None, None, try_func, &[data], None);
|
||||
// Return 0 unconditionally from the intrinsic call;
|
||||
// we can never unwind.
|
||||
let ret_align = bx.tcx.data_layout.i32_align.abi;
|
||||
@ -1204,21 +1204,21 @@ fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>,
|
||||
let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
|
||||
let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
bx.call(catch_ty, None, catch_func, &[data, ptr], None);
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
|
||||
bx.ret(bx.const_i32(1));
|
||||
|
||||
// NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
|
||||
// generate a try/catch.
|
||||
// FIXME(antoyo): add a check in the libgccjit API to prevent this.
|
||||
bx.switch_to_block(current_block);
|
||||
bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
|
||||
bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
|
||||
});
|
||||
|
||||
let func = unsafe { std::mem::transmute(func) };
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
// can't panic (that's what it's catching).
|
||||
let ret = bx.call(llty, None, func, &[try_func, data, catch_func], None);
|
||||
let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None);
|
||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||
bx.store(ret, dest, i32_align);
|
||||
}
|
||||
|
@ -280,16 +280,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
|
||||
// Unsupported.
|
||||
}
|
||||
|
||||
fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
|
||||
// Unsupported.
|
||||
self.context.new_rvalue_from_int(self.int_type, 0)
|
||||
}
|
||||
|
||||
fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) {
|
||||
// Unsupported.
|
||||
}
|
||||
}
|
||||
|
@ -443,9 +443,9 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||
);
|
||||
|
||||
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
|
||||
bx.invoke(fty, None, v, inputs, dest, catch, funclet)
|
||||
bx.invoke(fty, None, None, v, inputs, dest, catch, funclet)
|
||||
} else {
|
||||
bx.call(fty, None, v, inputs, None)
|
||||
bx.call(fty, None, None, v, inputs, None)
|
||||
};
|
||||
|
||||
// Store mark in a metadata node so we can map LLVM errors
|
||||
|
@ -15,14 +15,15 @@ use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_symbol_mangling::typeid::kcfi_typeid_for_fnabi;
|
||||
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
|
||||
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
|
||||
use rustc_target::spec::{HasTargetSpec, Target};
|
||||
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CStr;
|
||||
use std::iter;
|
||||
@ -216,6 +217,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
fn invoke(
|
||||
&mut self,
|
||||
llty: &'ll Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
args: &[&'ll Value],
|
||||
@ -230,19 +232,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
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() && let Some(fn_abi) = fn_abi && is_indirect_call {
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
|
||||
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);
|
||||
}
|
||||
// Emit CFI pointer type membership test
|
||||
self.cfi_type_test(fn_attrs, fn_abi, llfn);
|
||||
|
||||
// Emit KCFI operand bundle
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
|
||||
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
|
||||
bundles.push(kcfi_bundle);
|
||||
|
||||
bundles.retain(|bundle| bundle.is_some());
|
||||
let invoke = unsafe {
|
||||
@ -1183,6 +1179,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
fn call(
|
||||
&mut self,
|
||||
llty: &'ll Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
args: &[&'ll Value],
|
||||
@ -1195,19 +1192,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
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 let Some(fn_abi) = fn_abi && self.tcx.sess.is_sanitizer_kcfi_enabled() && is_indirect_call {
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
|
||||
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);
|
||||
}
|
||||
// Emit CFI pointer type membership test
|
||||
self.cfi_type_test(fn_attrs, fn_abi, llfn);
|
||||
|
||||
// Emit KCFI operand bundle
|
||||
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
|
||||
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
|
||||
bundles.push(kcfi_bundle);
|
||||
|
||||
bundles.retain(|bundle| bundle.is_some());
|
||||
let call = unsafe {
|
||||
@ -1456,7 +1447,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
|
||||
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
|
||||
let (ty, f) = self.cx.get_intrinsic(intrinsic);
|
||||
self.call(ty, None, f, args, None)
|
||||
self.call(ty, None, None, f, args, None)
|
||||
}
|
||||
|
||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
||||
@ -1518,7 +1509,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
|
||||
};
|
||||
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
|
||||
self.call(self.type_func(&[src_ty], dest_ty), None, f, &[val], None)
|
||||
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None)
|
||||
}
|
||||
|
||||
pub(crate) fn landing_pad(
|
||||
@ -1535,4 +1526,71 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
|
||||
}
|
||||
}
|
||||
|
||||
// Emits CFI pointer type membership tests.
|
||||
fn cfi_type_test(
|
||||
&mut self,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
) {
|
||||
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
|
||||
if is_indirect_call && fn_abi.is_some() && self.tcx.sess.is_sanitizer_cfi_enabled() {
|
||||
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::CFI) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut options = TypeIdOptions::empty();
|
||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||
}
|
||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
|
||||
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier.
|
||||
let cond = self.type_test(llfn, typeid_metadata);
|
||||
let bb_pass = self.append_sibling_block("type_test.pass");
|
||||
let bb_fail = self.append_sibling_block("type_test.fail");
|
||||
self.cond_br(cond, bb_pass, bb_fail);
|
||||
|
||||
self.switch_to_block(bb_fail);
|
||||
self.abort();
|
||||
self.unreachable();
|
||||
|
||||
self.switch_to_block(bb_pass);
|
||||
}
|
||||
}
|
||||
|
||||
// Emits KCFI operand bundles.
|
||||
fn kcfi_operand_bundle(
|
||||
&mut self,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: &'ll Value,
|
||||
) -> Option<llvm::OperandBundleDef<'ll>> {
|
||||
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
|
||||
let kcfi_bundle = if is_indirect_call && self.tcx.sess.is_sanitizer_kcfi_enabled() {
|
||||
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::KCFI) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut options = TypeIdOptions::empty();
|
||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||
}
|
||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
|
||||
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
kcfi_bundle
|
||||
}
|
||||
}
|
||||
|
@ -228,18 +228,29 @@ pub unsafe fn create_module<'ll>(
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_enabled() {
|
||||
// FIXME(rcvalle): Add support for non canonical jump tables.
|
||||
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
|
||||
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
|
||||
// FIXME(rcvalle): Add it with Override behavior flag.
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
|
||||
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
|
||||
let enable_split_lto_unit = "EnableSplitLTOUnit\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi = "kcfi\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
|
@ -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::{kcfi_typeid_for_fnabi, typeid_for_fnabi};
|
||||
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// Declare a function.
|
||||
@ -132,12 +132,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
fn_abi.apply_attrs_llfn(self, llfn);
|
||||
|
||||
if self.tcx.sess.is_sanitizer_cfi_enabled() {
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
|
||||
self.set_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(
|
||||
self.tcx,
|
||||
fn_abi,
|
||||
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
|
||||
);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
}
|
||||
|
||||
if self.tcx.sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
|
||||
// LLVM KCFI does not support multiple !kcfi_type attachments
|
||||
let mut options = TypeIdOptions::empty();
|
||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||
}
|
||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
self.set_kcfi_type_metadata(llfn, kcfi_typeid);
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
self.call(
|
||||
simple_ty,
|
||||
None,
|
||||
None,
|
||||
simple_fn,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None,
|
||||
@ -444,7 +445,7 @@ fn try_intrinsic<'ll>(
|
||||
) {
|
||||
if bx.sess().panic_strategy() == PanicStrategy::Abort {
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.call(try_func_ty, None, try_func, &[data], None);
|
||||
bx.call(try_func_ty, None, None, try_func, &[data], None);
|
||||
// Return 0 unconditionally from the intrinsic call;
|
||||
// we can never unwind.
|
||||
let ret_align = bx.tcx().data_layout.i32_align.abi;
|
||||
@ -543,7 +544,7 @@ fn codegen_msvc_try<'ll>(
|
||||
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||
let slot = bx.alloca(bx.type_i8p(), ptr_align);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, None, try_func, &[data], normal, catchswitch, None);
|
||||
bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
|
||||
|
||||
bx.switch_to_block(normal);
|
||||
bx.ret(bx.const_i32(0));
|
||||
@ -587,7 +588,7 @@ fn codegen_msvc_try<'ll>(
|
||||
let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
|
||||
let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
bx.call(catch_ty, None, catch_func, &[data, ptr], Some(&funclet));
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
|
||||
bx.catch_ret(&funclet, caught);
|
||||
|
||||
// The flag value of 64 indicates a "catch-all".
|
||||
@ -595,7 +596,7 @@ fn codegen_msvc_try<'ll>(
|
||||
let flags = bx.const_i32(64);
|
||||
let null = bx.const_null(bx.type_i8p());
|
||||
let funclet = bx.catch_pad(cs, &[null, flags, null]);
|
||||
bx.call(catch_ty, None, catch_func, &[data, null], Some(&funclet));
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet));
|
||||
bx.catch_ret(&funclet, caught);
|
||||
|
||||
bx.switch_to_block(caught);
|
||||
@ -604,7 +605,7 @@ fn codegen_msvc_try<'ll>(
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
// can't panic (that's what it's catching).
|
||||
let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
|
||||
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
|
||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||
bx.store(ret, dest, i32_align);
|
||||
}
|
||||
@ -647,7 +648,7 @@ fn codegen_gnu_try<'ll>(
|
||||
let data = llvm::get_param(bx.llfn(), 1);
|
||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
|
||||
bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
|
||||
|
||||
bx.switch_to_block(then);
|
||||
bx.ret(bx.const_i32(0));
|
||||
@ -665,13 +666,13 @@ fn codegen_gnu_try<'ll>(
|
||||
bx.add_clause(vals, tydesc);
|
||||
let ptr = bx.extract_value(vals, 0);
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
bx.call(catch_ty, None, catch_func, &[data, ptr], None);
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
|
||||
bx.ret(bx.const_i32(1));
|
||||
});
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
// can't panic (that's what it's catching).
|
||||
let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
|
||||
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
|
||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||
bx.store(ret, dest, i32_align);
|
||||
}
|
||||
@ -711,7 +712,7 @@ fn codegen_emcc_try<'ll>(
|
||||
let data = llvm::get_param(bx.llfn(), 1);
|
||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
|
||||
bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
|
||||
|
||||
bx.switch_to_block(then);
|
||||
bx.ret(bx.const_i32(0));
|
||||
@ -750,13 +751,13 @@ fn codegen_emcc_try<'ll>(
|
||||
let catch_data = bx.bitcast(catch_data, bx.type_i8p());
|
||||
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
bx.call(catch_ty, None, catch_func, &[data, catch_data], None);
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None);
|
||||
bx.ret(bx.const_i32(1));
|
||||
});
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
// can't panic (that's what it's catching).
|
||||
let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
|
||||
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
|
||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||
bx.store(ret, dest, i32_align);
|
||||
}
|
||||
@ -1205,6 +1206,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
let c = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None,
|
||||
@ -1423,6 +1425,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[1].immediate(), alignment, mask, args[0].immediate()],
|
||||
None,
|
||||
@ -1564,6 +1567,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[0].immediate(), args[1].immediate(), alignment, mask],
|
||||
None,
|
||||
@ -2037,7 +2041,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
|
||||
let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(fn_ty, None, f, &[lhs, rhs], None);
|
||||
let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None);
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
|
@ -291,8 +291,24 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn add_type_metadata(&self, function: &'ll Value, typeid: String) {
|
||||
let typeid_metadata = self.typeid_metadata(typeid).unwrap();
|
||||
let v = [self.const_usize(0), typeid_metadata];
|
||||
unsafe {
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
|
||||
self.llcx,
|
||||
v.as_ptr(),
|
||||
v.len() as c_uint,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
|
||||
let typeid_metadata = self.typeid_metadata(typeid);
|
||||
let typeid_metadata = self.typeid_metadata(typeid).unwrap();
|
||||
let v = [self.const_usize(0), typeid_metadata];
|
||||
unsafe {
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
@ -307,13 +323,28 @@ impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn typeid_metadata(&self, typeid: String) -> &'ll Value {
|
||||
unsafe {
|
||||
fn typeid_metadata(&self, typeid: String) -> Option<&'ll Value> {
|
||||
Some(unsafe {
|
||||
llvm::LLVMMDStringInContext(
|
||||
self.llcx,
|
||||
typeid.as_ptr() as *const c_char,
|
||||
typeid.len() as c_uint,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
let kcfi_type_metadata = self.const_u32(kcfi_typeid);
|
||||
unsafe {
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
1,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,7 +494,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
(rust_main, start_ty, vec![arg_argc, arg_argv])
|
||||
};
|
||||
|
||||
let result = bx.call(start_ty, None, start_fn, &args, None);
|
||||
let result = bx.call(start_ty, None, None, start_fn, &args, None);
|
||||
let cast = bx.intcast(result, cx.type_int(), true);
|
||||
bx.ret(cast);
|
||||
|
||||
|
@ -28,8 +28,9 @@ impl<'a, 'tcx> VirtualIndex {
|
||||
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
|
||||
&& bx.cx().sess().lto() == Lto::Fat
|
||||
{
|
||||
let typeid =
|
||||
bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)));
|
||||
let typeid = bx
|
||||
.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)))
|
||||
.unwrap();
|
||||
let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
bx.pointercast(func, llty)
|
||||
|
@ -19,7 +19,6 @@ use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{sym, Symbol};
|
||||
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
|
||||
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
|
||||
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -163,6 +162,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
// do an invoke, otherwise do a call.
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
||||
let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
|
||||
Some(bx.tcx().codegen_fn_attrs(fx.instance.def_id()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if !fn_abi.can_unwind {
|
||||
unwind = mir::UnwindAction::Unreachable;
|
||||
}
|
||||
@ -190,6 +195,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
};
|
||||
let invokeret = bx.invoke(
|
||||
fn_ty,
|
||||
fn_attrs,
|
||||
Some(&fn_abi),
|
||||
fn_ptr,
|
||||
&llargs,
|
||||
@ -211,7 +217,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||
}
|
||||
MergingSucc::False
|
||||
} else {
|
||||
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &llargs, self.funclet(fx));
|
||||
let llret = bx.call(fn_ty, fn_attrs, Some(&fn_abi), fn_ptr, &llargs, self.funclet(fx));
|
||||
if fx.mir[self.bb].is_cleanup {
|
||||
// Cleanup is always the cold path. Don't inline
|
||||
// drop glue. Also, when there is a deeply-nested
|
||||
@ -1051,48 +1057,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.codegen_argument(bx, location, &mut llargs, last_arg);
|
||||
}
|
||||
|
||||
let (is_indirect_call, fn_ptr) = match (llfn, instance) {
|
||||
(Some(llfn), _) => (true, llfn),
|
||||
(None, Some(instance)) => (false, bx.get_fn_addr(instance)),
|
||||
_ => span_bug!(span, "no llfn for call"),
|
||||
let fn_ptr = match (instance, llfn) {
|
||||
(Some(instance), None) => bx.get_fn_addr(instance),
|
||||
(_, Some(llfn)) => llfn,
|
||||
_ => span_bug!(span, "no instance or llfn for call"),
|
||||
};
|
||||
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given
|
||||
// pointer is associated with a type identifier).
|
||||
if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
|
||||
// Emit type metadata and checks.
|
||||
// FIXME(rcvalle): Add support for generalized identifiers.
|
||||
// FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
|
||||
let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
|
||||
let typeid_metadata = self.cx.typeid_metadata(typeid);
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier.
|
||||
let cond = bx.type_test(fn_ptr, typeid_metadata);
|
||||
let bb_pass = bx.append_sibling_block("type_test.pass");
|
||||
let bb_fail = bx.append_sibling_block("type_test.fail");
|
||||
bx.cond_br(cond, bb_pass, bb_fail);
|
||||
|
||||
bx.switch_to_block(bb_pass);
|
||||
let merging_succ = helper.do_call(
|
||||
self,
|
||||
bx,
|
||||
fn_abi,
|
||||
fn_ptr,
|
||||
&llargs,
|
||||
target.as_ref().map(|&target| (ret_dest, target)),
|
||||
unwind,
|
||||
&copied_constant_arguments,
|
||||
false,
|
||||
);
|
||||
assert_eq!(merging_succ, MergingSucc::False);
|
||||
|
||||
bx.switch_to_block(bb_fail);
|
||||
bx.abort();
|
||||
bx.unreachable();
|
||||
|
||||
return MergingSucc::False;
|
||||
}
|
||||
|
||||
helper.do_call(
|
||||
self,
|
||||
bx,
|
||||
@ -1640,7 +1610,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
||||
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
bx.do_not_inline(llret);
|
||||
|
||||
bx.unreachable();
|
||||
|
@ -697,7 +697,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let fn_ptr = bx.get_fn_addr(instance);
|
||||
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None)
|
||||
let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {
|
||||
Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None)
|
||||
} else {
|
||||
bx.get_static(def_id)
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ use crate::mir::operand::OperandRef;
|
||||
use crate::mir::place::PlaceRef;
|
||||
use crate::MemFlags;
|
||||
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
@ -72,6 +73,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
||||
fn invoke(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
@ -321,6 +323,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
||||
fn call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
llfn: Self::Value,
|
||||
args: &[Self::Value],
|
||||
|
@ -128,12 +128,16 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
|
||||
) -> Self::Type;
|
||||
}
|
||||
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given pointer is
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given pointer is
|
||||
// associated with a type identifier).
|
||||
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);
|
||||
fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {}
|
||||
fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {}
|
||||
fn typeid_metadata(&self, _typeid: String) -> Option<Self::Value> {
|
||||
None
|
||||
}
|
||||
fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
|
||||
fn set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
|
||||
}
|
||||
|
||||
pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
|
||||
|
@ -331,6 +331,8 @@ declare_features! (
|
||||
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
|
||||
/// Allow conditional compilation depending on rust version
|
||||
(active, cfg_version, "1.45.0", Some(64796), None),
|
||||
/// Allows to use the `#[cfi_encoding = ""]` attribute.
|
||||
(active, cfi_encoding, "1.69.0", Some(89653), None),
|
||||
/// Allows `for<...>` on closures and generators.
|
||||
(active, closure_lifetime_binder, "1.64.0", Some(97362), None),
|
||||
/// Allows `#[track_caller]` on closures and generators.
|
||||
|
@ -494,6 +494,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
// RFC 2397
|
||||
gated!(do_not_recommend, Normal, template!(Word), WarnFollowing, experimental!(do_not_recommend)),
|
||||
|
||||
// `#[cfi_encoding = ""]`
|
||||
gated!(
|
||||
cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
|
||||
experimental!(cfi_encoding)
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Stability, deprecation, and unsafe:
|
||||
// ==========================================================================
|
||||
|
@ -226,6 +226,7 @@ language_item_table! {
|
||||
|
||||
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
|
||||
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
|
||||
|
@ -795,12 +795,16 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
||||
tracked!(report_delayed_bugs, true);
|
||||
tracked!(sanitizer, SanitizerSet::ADDRESS);
|
||||
tracked!(sanitizer_cfi_canonical_jump_tables, None);
|
||||
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
|
||||
tracked!(sanitizer_cfi_normalize_integers, Some(true));
|
||||
tracked!(sanitizer_memory_track_origins, 2);
|
||||
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
|
||||
tracked!(saturating_float_casts, Some(true));
|
||||
tracked!(share_generics, Some(true));
|
||||
tracked!(show_span, Some(String::from("abc")));
|
||||
tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
|
||||
tracked!(split_lto_unit, Some(true));
|
||||
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
|
||||
tracked!(stack_protector, StackProtector::All);
|
||||
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
|
||||
|
@ -2400,6 +2400,13 @@ impl<'tcx> Ty<'tcx> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_c_void(self, tcx: TyCtxt<'_>) -> bool {
|
||||
match self.kind() {
|
||||
ty::Adt(adt, _) => tcx.lang_items().get(LangItem::CVoid) == Some(adt.did()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extra information about why we ended up with a particular variance.
|
||||
|
@ -35,7 +35,15 @@ session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible
|
||||
|
||||
session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
|
||||
|
||||
session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto`
|
||||
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
|
||||
|
||||
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
|
||||
|
||||
|
@ -1036,6 +1036,14 @@ fn default_configuration(sess: &Session) -> CrateConfig {
|
||||
ret.insert((sym::sanitize, Some(symbol)));
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
ret.insert((sym::sanitizer_cfi_generalize_pointers, None));
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
ret.insert((sym::sanitizer_cfi_normalize_integers, None));
|
||||
}
|
||||
|
||||
if sess.opts.debug_assertions {
|
||||
ret.insert((sym::debug_assertions, None));
|
||||
}
|
||||
|
@ -111,8 +111,24 @@ pub struct CannotMixAndMatchSanitizers {
|
||||
pub struct CannotEnableCrtStaticLinux;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_enabled)]
|
||||
pub struct SanitizerCfiEnabled;
|
||||
#[diag(session_sanitizer_cfi_requires_lto)]
|
||||
pub struct SanitizerCfiRequiresLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
|
||||
pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_generalize_pointers_requires_cfi)]
|
||||
pub struct SanitizerCfiGeneralizePointersRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
|
||||
pub struct SanitizerCfiNormalizeIntegersRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_split_lto_unit_requires_lto)]
|
||||
pub struct SplitLtoUnitRequiresLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unstable_virtual_function_elimination)]
|
||||
|
@ -1662,6 +1662,12 @@ options! {
|
||||
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
"use a sanitizer"),
|
||||
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
|
||||
"enable canonical jump tables (default: yes)"),
|
||||
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable generalizing pointer types (default: no)"),
|
||||
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable normalizing integer types (default: no)"),
|
||||
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
||||
"enable origins tracking in MemorySanitizer"),
|
||||
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
@ -1707,6 +1713,8 @@ options! {
|
||||
file which is ignored by the linker
|
||||
`single`: sections which do not require relocation are written into object file but ignored
|
||||
by the linker"),
|
||||
split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable LTO unit splitting (default: no)"),
|
||||
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
|
||||
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
|
||||
|
@ -766,10 +766,30 @@ impl Session {
|
||||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
|
||||
}
|
||||
|
||||
pub fn is_split_lto_unit_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.split_lto_unit == Some(true)
|
||||
}
|
||||
|
||||
/// Check whether this compile session and crate type use static crt.
|
||||
pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
|
||||
if !self.target.crt_static_respected {
|
||||
@ -1582,17 +1602,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||
sess.emit_err(errors::CannotEnableCrtStaticLinux);
|
||||
}
|
||||
|
||||
// LLVM CFI and VFE both require LTO.
|
||||
if sess.lto() != config::Lto::Fat {
|
||||
if sess.is_sanitizer_cfi_enabled() {
|
||||
sess.emit_err(errors::SanitizerCfiEnabled);
|
||||
}
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
sess.emit_err(errors::UnstableVirtualFunctionElimination);
|
||||
}
|
||||
// LLVM CFI requires LTO.
|
||||
if sess.is_sanitizer_cfi_enabled()
|
||||
&& !(sess.lto() == config::Lto::Fat
|
||||
|| sess.lto() == config::Lto::Thin
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled())
|
||||
{
|
||||
sess.emit_err(errors::SanitizerCfiRequiresLto);
|
||||
}
|
||||
|
||||
// LLVM CFI and KCFI are mutually exclusive
|
||||
// LLVM CFI is incompatible with LLVM KCFI.
|
||||
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
|
||||
sess.emit_err(errors::CannotMixAndMatchSanitizers {
|
||||
first: "cfi".to_string(),
|
||||
@ -1600,6 +1619,43 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||
});
|
||||
}
|
||||
|
||||
// Canonical jump tables requires CFI.
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
|
||||
if !sess.is_sanitizer_cfi_enabled() {
|
||||
sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LLVM CFI pointer generalization requires CFI or KCFI.
|
||||
if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
|
||||
sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LLVM CFI integer normalization requires CFI or KCFI.
|
||||
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
|
||||
sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LTO unit splitting requires LTO.
|
||||
if sess.is_split_lto_unit_enabled()
|
||||
&& !(sess.lto() == config::Lto::Fat
|
||||
|| sess.lto() == config::Lto::Thin
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled())
|
||||
{
|
||||
sess.emit_err(errors::SplitLtoUnitRequiresLto);
|
||||
}
|
||||
|
||||
// VFE requires LTO.
|
||||
if sess.lto() != config::Lto::Fat {
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
sess.emit_err(errors::UnstableVirtualFunctionElimination);
|
||||
}
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.stack_protector != StackProtector::None {
|
||||
if !sess.target.options.supports_stack_protector {
|
||||
sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
|
||||
|
@ -443,6 +443,7 @@ symbols! {
|
||||
c_str,
|
||||
c_unwind,
|
||||
c_variadic,
|
||||
c_void,
|
||||
call,
|
||||
call_mut,
|
||||
call_once,
|
||||
@ -470,6 +471,7 @@ symbols! {
|
||||
cfg_target_vendor,
|
||||
cfg_version,
|
||||
cfi,
|
||||
cfi_encoding,
|
||||
char,
|
||||
client,
|
||||
clippy,
|
||||
@ -1323,6 +1325,8 @@ symbols! {
|
||||
s,
|
||||
safety,
|
||||
sanitize,
|
||||
sanitizer_cfi_generalize_pointers,
|
||||
sanitizer_cfi_normalize_integers,
|
||||
sanitizer_runtime,
|
||||
saturating_add,
|
||||
saturating_sub,
|
||||
|
@ -1,42 +1,65 @@
|
||||
// For more information about type metadata and type metadata identifiers for cross-language LLVM
|
||||
// CFI support, see Type metadata in the design document in the tracking issue #89653.
|
||||
|
||||
/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI
|
||||
/// support.
|
||||
///
|
||||
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
|
||||
/// see design document in the tracking issue #89653.
|
||||
use bitflags::bitflags;
|
||||
use rustc_middle::ty::{FnSig, Ty, TyCtxt};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use std::hash::Hasher;
|
||||
use twox_hash::XxHash64;
|
||||
|
||||
bitflags! {
|
||||
/// Options for typeid_for_fnabi and typeid_for_fnsig.
|
||||
pub struct TypeIdOptions: u32 {
|
||||
const GENERALIZE_POINTERS = 1;
|
||||
const GENERALIZE_REPR_C = 2;
|
||||
const NORMALIZE_INTEGERS = 4;
|
||||
}
|
||||
}
|
||||
|
||||
mod typeid_itanium_cxx_abi;
|
||||
use typeid_itanium_cxx_abi::TypeIdOptions;
|
||||
|
||||
/// Returns a type metadata identifier for the specified FnAbi.
|
||||
pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
|
||||
typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
|
||||
pub fn typeid_for_fnabi<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
|
||||
}
|
||||
|
||||
/// Returns a type metadata identifier for the specified FnSig.
|
||||
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)
|
||||
pub fn typeid_for_fnsig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: &FnSig<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, 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.)
|
||||
/// Returns a KCFI type metadata identifier for the specified FnAbi.
|
||||
pub fn kcfi_typeid_for_fnabi<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
options: TypeIdOptions,
|
||||
) -> u32 {
|
||||
// A 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.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, 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.)
|
||||
/// Returns a KCFI type metadata identifier for the specified FnSig.
|
||||
pub fn kcfi_typeid_for_fnsig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: &FnSig<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> u32 {
|
||||
// A 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.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
|
||||
hash.finish() as u32
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
// For more information about type metadata and type metadata identifiers for cross-language LLVM
|
||||
// CFI support, see Type metadata in the design document in the tracking issue #89653.
|
||||
|
||||
// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
|
||||
// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
|
||||
// calling convention to use this encoding for cross-language LLVM CFI.
|
||||
|
||||
use bitflags::bitflags;
|
||||
/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow
|
||||
/// Integrity (CFI) and cross-language LLVM CFI support.
|
||||
///
|
||||
/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
|
||||
/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
|
||||
/// are not used across the FFI boundary.
|
||||
///
|
||||
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
|
||||
/// see design document in the tracking issue #89653.
|
||||
use core::fmt::Display;
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::DiagnosticMessage;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
@ -16,11 +18,13 @@ use rustc_middle::ty::{
|
||||
Ty, TyCtxt, UintTy,
|
||||
};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::abi::call::{Conv, FnAbi};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use crate::typeid::TypeIdOptions;
|
||||
|
||||
/// Type and extended type qualifiers.
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
enum TyQ {
|
||||
@ -38,15 +42,6 @@ enum DictKey<'tcx> {
|
||||
Predicate(ExistentialPredicate<'tcx>),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Options for typeid_for_fnabi and typeid_for_fnsig.
|
||||
pub struct TypeIdOptions: u32 {
|
||||
const NO_OPTIONS = 0;
|
||||
const GENERALIZE_POINTERS = 1;
|
||||
const GENERALIZE_REPR_C = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for encode_ty.
|
||||
type EncodeTyOptions = TypeIdOptions;
|
||||
|
||||
@ -91,21 +86,6 @@ fn compress<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
|
||||
// along with other is_c_type methods.
|
||||
/// Returns whether a `ty::Ty` is `c_void`.
|
||||
fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Adt(adt_def, ..) => {
|
||||
let def_id = adt_def.0.did;
|
||||
let crate_name = tcx.crate_name(def_id.krate);
|
||||
tcx.item_name(def_id).as_str() == "c_void"
|
||||
&& (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes a const using the Itanium C++ ABI as a literal argument (see
|
||||
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
|
||||
fn encode_const<'tcx>(
|
||||
@ -448,6 +428,12 @@ fn encode_ty<'tcx>(
|
||||
|
||||
match ty.kind() {
|
||||
// Primitive types
|
||||
|
||||
// Rust's bool has the same layout as C17's _Bool, that is, its size and alignment are
|
||||
// implementation-defined. Any bool can be cast into an integer, taking on the values 1
|
||||
// (true) or 0 (false).
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
|
||||
ty::Bool => {
|
||||
typeid.push('b');
|
||||
}
|
||||
@ -535,9 +521,33 @@ fn encode_ty<'tcx>(
|
||||
// User-defined types
|
||||
ty::Adt(adt_def, substs) => {
|
||||
let mut s = String::new();
|
||||
let def_id = adt_def.0.did;
|
||||
if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
|
||||
// For cross-language CFI support, the encoding must be compatible at the FFI
|
||||
let def_id = adt_def.did();
|
||||
if let Some(cfi_encoding) = tcx.get_attr(def_id, sym::cfi_encoding) {
|
||||
// Use user-defined CFI encoding for type
|
||||
if let Some(value_str) = cfi_encoding.value_str() {
|
||||
if !value_str.to_string().trim().is_empty() {
|
||||
s.push_str(&value_str.to_string().trim());
|
||||
} else {
|
||||
#[allow(
|
||||
rustc::diagnostic_outside_of_impl,
|
||||
rustc::untranslatable_diagnostic
|
||||
)]
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
cfi_encoding.span,
|
||||
DiagnosticMessage::Str(format!(
|
||||
"invalid `cfi_encoding` for `{:?}`",
|
||||
ty.kind()
|
||||
)),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else {
|
||||
bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
|
||||
}
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
} else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
|
||||
// For cross-language LLVM CFI support, the encoding must be compatible at the FFI
|
||||
// boundary. For instance:
|
||||
//
|
||||
// struct type1 {};
|
||||
@ -567,8 +577,33 @@ fn encode_ty<'tcx>(
|
||||
ty::Foreign(def_id) => {
|
||||
// <length><name>, where <name> is <unscoped-name>
|
||||
let mut s = String::new();
|
||||
let name = tcx.item_name(*def_id).to_string();
|
||||
let _ = write!(s, "{}{}", name.len(), &name);
|
||||
if let Some(cfi_encoding) = tcx.get_attr(*def_id, sym::cfi_encoding) {
|
||||
// Use user-defined CFI encoding for type
|
||||
if let Some(value_str) = cfi_encoding.value_str() {
|
||||
if !value_str.to_string().trim().is_empty() {
|
||||
s.push_str(&value_str.to_string().trim());
|
||||
} else {
|
||||
#[allow(
|
||||
rustc::diagnostic_outside_of_impl,
|
||||
rustc::untranslatable_diagnostic
|
||||
)]
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
cfi_encoding.span,
|
||||
DiagnosticMessage::Str(format!(
|
||||
"invalid `cfi_encoding` for `{:?}`",
|
||||
ty.kind()
|
||||
)),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else {
|
||||
bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
|
||||
}
|
||||
} else {
|
||||
let name = tcx.item_name(*def_id).to_string();
|
||||
let _ = write!(s, "{}{}", name.len(), &name);
|
||||
}
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
}
|
||||
@ -618,7 +653,7 @@ fn encode_ty<'tcx>(
|
||||
ty::FnPtr(fn_sig) => {
|
||||
// PF<return-type><parameter-type1..parameter-typeN>E
|
||||
let mut s = String::from("P");
|
||||
s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
|
||||
s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::empty()));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
}
|
||||
@ -655,22 +690,59 @@ fn encode_ty<'tcx>(
|
||||
}
|
||||
|
||||
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
|
||||
// c_void types into unit types unconditionally, and generalizes all pointers if
|
||||
// TransformTyOptions::GENERALIZE_POINTERS option is set.
|
||||
#[instrument(level = "trace", skip(tcx))]
|
||||
// c_void types into unit types unconditionally, generalizes pointers if
|
||||
// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
|
||||
// TransformTyOptions::NORMALIZE_INTEGERS option is set.
|
||||
fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
|
||||
let mut ty = ty;
|
||||
|
||||
match ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Char
|
||||
| ty::Str
|
||||
| ty::Never
|
||||
| ty::Foreign(..)
|
||||
| ty::Dynamic(..) => {}
|
||||
ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) | ty::Dynamic(..) => {}
|
||||
|
||||
ty::Bool => {
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: on all platforms that Rust's currently supports, its size and alignment are
|
||||
// 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
|
||||
//
|
||||
// Clang represents bool as an 8-bit unsigned integer.
|
||||
ty = tcx.types.u8;
|
||||
}
|
||||
}
|
||||
|
||||
ty::Int(..) | ty::Uint(..) => {
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
|
||||
// All platforms we currently support have a C platform, and as a consequence,
|
||||
// isize/usize are at least 16-bit wide for all of them.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
|
||||
match ty.kind() {
|
||||
ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
|
||||
16 => ty = tcx.types.i16,
|
||||
32 => ty = tcx.types.i32,
|
||||
64 => ty = tcx.types.i64,
|
||||
128 => ty = tcx.types.i128,
|
||||
_ => bug!(
|
||||
"transform_ty: unexpected pointer width `{}`",
|
||||
tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
|
||||
16 => ty = tcx.types.u16,
|
||||
32 => ty = tcx.types.u32,
|
||||
64 => ty = tcx.types.u64,
|
||||
128 => ty = tcx.types.u128,
|
||||
_ => bug!(
|
||||
"transform_ty: unexpected pointer width `{}`",
|
||||
tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ if ty.is_unit() => {}
|
||||
|
||||
@ -688,12 +760,17 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
|
||||
}
|
||||
|
||||
ty::Adt(adt_def, substs) => {
|
||||
if is_c_void_ty(tcx, ty) {
|
||||
if ty.is_c_void(tcx) {
|
||||
ty = tcx.mk_unit();
|
||||
} else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
|
||||
{
|
||||
ty = tcx.mk_adt(*adt_def, ty::List::empty());
|
||||
} else if adt_def.repr().transparent() && adt_def.is_struct() {
|
||||
// Don't transform repr(transparent) types with an user-defined CFI encoding to
|
||||
// preserve the user-defined CFI encoding.
|
||||
if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
|
||||
return ty;
|
||||
}
|
||||
let variant = adt_def.non_enum_variant();
|
||||
let param_env = tcx.param_env(variant.def_id);
|
||||
let field = variant.fields.iter().find(|field| {
|
||||
@ -815,7 +892,7 @@ fn transform_substs<'tcx>(
|
||||
options: TransformTyOptions,
|
||||
) -> SubstsRef<'tcx> {
|
||||
let substs = substs.iter().map(|subst| match subst.unpack() {
|
||||
GenericArgKind::Type(ty) if is_c_void_ty(tcx, ty) => tcx.mk_unit().into(),
|
||||
GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(),
|
||||
GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(),
|
||||
_ => subst,
|
||||
});
|
||||
@ -887,6 +964,15 @@ pub fn typeid_for_fnabi<'tcx>(
|
||||
// Close the "F..E" pair
|
||||
typeid.push('E');
|
||||
|
||||
// Add encoding suffixes
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
typeid.push_str(".normalized");
|
||||
}
|
||||
|
||||
if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
|
||||
typeid.push_str(".generalized");
|
||||
}
|
||||
|
||||
typeid
|
||||
}
|
||||
|
||||
@ -913,5 +999,14 @@ pub fn typeid_for_fnsig<'tcx>(
|
||||
// Encode the function signature
|
||||
typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));
|
||||
|
||||
// Add encoding suffixes
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
typeid.push_str(".normalized");
|
||||
}
|
||||
|
||||
if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
|
||||
typeid.push_str(".generalized");
|
||||
}
|
||||
|
||||
typeid
|
||||
}
|
||||
|
@ -202,6 +202,7 @@ mod c_long_definition {
|
||||
// would be uninhabited and at least dereferencing such pointers would
|
||||
// be UB.
|
||||
#[doc = include_str!("c_void.md")]
|
||||
#[cfg_attr(not(bootstrap), lang = "c_void")]
|
||||
#[repr(u8)]
|
||||
#[stable(feature = "core_c_void", since = "1.30.0")]
|
||||
pub enum c_void {
|
||||
|
@ -196,18 +196,18 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
|
||||
|
||||
# ControlFlowIntegrity
|
||||
|
||||
The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
|
||||
provides forward-edge control flow protection for Rust-compiled code only by
|
||||
aggregating function pointers in groups identified by their return and parameter
|
||||
types.
|
||||
The LLVM Control Flow Integrity (CFI) support in the Rust compiler provides
|
||||
forward-edge control flow protection for both Rust-compiled code only and for C
|
||||
or C++ and Rust -compiled code mixed-language binaries, also known as “mixed
|
||||
binaries” (i.e., for when C or C++ and Rust -compiled code share the same
|
||||
virtual address space), by aggregating function pointers in groups identified by
|
||||
their return and parameter types.
|
||||
|
||||
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 by defining and using
|
||||
compatible type identifiers (see Type metadata in the design document in the
|
||||
tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
|
||||
|
||||
LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
|
||||
LLVM CFI can be enabled with `-Zsanitizer=cfi` and requires LTO (i.e., `-Clto`).
|
||||
Cross-language LLVM CFI can be enabled with `-Zsanitizer=cfi`, and requires the
|
||||
`-Zsanitizer-cfi-normalize-integers` option to be used with Clang
|
||||
`-fsanitize-cfi-icall-normalize-integers` for normalizing integer types, and
|
||||
proper (i.e., non-rustc) LTO (i.e., `-Clinker-plugin-lto`).
|
||||
|
||||
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
|
||||
|
||||
@ -343,7 +343,7 @@ $
|
||||
Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
|
||||
|
||||
```shell
|
||||
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
|
||||
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
|
||||
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
|
||||
Finished release [optimized] target(s) in 3.38s
|
||||
Running `target/release/rust-cfi-2`
|
||||
@ -392,7 +392,7 @@ Closures][rust-book-ch19-05] chapter of the [The Rust Programming
|
||||
Language][rust-book] book.
|
||||
|
||||
```shell
|
||||
cargo run --release
|
||||
$ cargo run --release
|
||||
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
|
||||
Finished release [optimized] target(s) in 0.74s
|
||||
Running `target/release/rust-cfi-3`
|
||||
@ -404,7 +404,7 @@ $
|
||||
Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
|
||||
|
||||
```shell
|
||||
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
|
||||
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
|
||||
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
|
||||
Finished release [optimized] target(s) in 3.40s
|
||||
Running `target/release/rust-cfi-3`
|
||||
@ -420,8 +420,92 @@ flow using an indirect branch/call to a function with different return and
|
||||
parameter types than the return type expected and arguments intended/passed in
|
||||
the call/branch site, the execution is also terminated (see Fig. 9).
|
||||
|
||||
[rust-book-ch19-05]: ../../book/ch19-05-advanced-functions-and-closures.html
|
||||
[rust-book]: ../../book/title-page.html
|
||||
```ignore (cannot-test-this-because-uses-custom-build)
|
||||
int
|
||||
do_twice(int (*fn)(int), int arg) {
|
||||
return fn(arg) + fn(arg);
|
||||
}
|
||||
```
|
||||
Fig. 10. Example C library.
|
||||
|
||||
```ignore (cannot-test-this-because-uses-custom-build)
|
||||
use std::mem;
|
||||
|
||||
#[link(name = "foo")]
|
||||
extern "C" {
|
||||
fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32;
|
||||
}
|
||||
|
||||
unsafe extern "C" fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
unsafe extern "C" fn add_two(x: i64) -> i64 {
|
||||
x + 2
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let answer = unsafe { do_twice(add_one, 5) };
|
||||
|
||||
println!("The answer is: {}", answer);
|
||||
|
||||
println!("With CFI enabled, you should not see the next answer");
|
||||
let f: unsafe extern "C" fn(i32) -> i32 = unsafe {
|
||||
mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8)
|
||||
};
|
||||
let next_answer = unsafe { do_twice(f, 5) };
|
||||
|
||||
println!("The next answer is: {}", next_answer);
|
||||
}
|
||||
```
|
||||
Fig. 11. Another modified example from the [Advanced Functions and
|
||||
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
|
||||
Language][rust-book] book.
|
||||
|
||||
```shell
|
||||
$ make
|
||||
mkdir -p target/debug
|
||||
clang -I. -Isrc -Wall -flto -fvisibility=hidden -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
|
||||
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
|
||||
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build
|
||||
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
|
||||
$ ./target/debug/main
|
||||
The answer is: 12
|
||||
With CFI enabled, you should not see the next answer
|
||||
The next answer is: 14
|
||||
$
|
||||
```
|
||||
Fig. 12. Build and execution of the modified example with LLVM CFI disabled.
|
||||
|
||||
```shell
|
||||
$ make
|
||||
mkdir -p target/debug
|
||||
clang -I. -Isrc -Wall -flto -fvisibility=hidden -fsanitize=cfi -fsanitize-cfi-icall-normalize-integers -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
|
||||
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
|
||||
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers" cargo build
|
||||
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
|
||||
$ ./target/debug/main
|
||||
The answer is: 12
|
||||
With CFI enabled, you should not see the next answer
|
||||
Illegal instruction
|
||||
$
|
||||
```
|
||||
Fig. 13. Build and execution of the modified example with LLVM CFI enabled.
|
||||
|
||||
When LLVM CFI is enabled, if there are any attempts to change/hijack control
|
||||
flow using an indirect branch/call to a function with different return and
|
||||
parameter types than the return type expected and arguments intended/passed in
|
||||
the call/branch site, even across the FFI boundary and for extern "C" function
|
||||
types indirectly called (i.e., callbacks/function pointers) across the FFI
|
||||
boundary, in C or C++ and Rust -compiled code mixed-language binaries, also
|
||||
known as “mixed binaries” (i.e., for when C or C++ and Rust -compiled code share
|
||||
the same virtual address space), the execution is also terminated (see Fig. 13).
|
||||
|
||||
|
||||
[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
|
||||
[rust-book]: https://doc.rust-lang.org/book/title-page.html
|
||||
|
||||
# HWAddressSanitizer
|
||||
|
||||
|
25
src/doc/unstable-book/src/language-features/cfi-encoding.md
Normal file
25
src/doc/unstable-book/src/language-features/cfi-encoding.md
Normal file
@ -0,0 +1,25 @@
|
||||
# `cfi_encoding`
|
||||
|
||||
The tracking issue for this feature is: [#89653]
|
||||
|
||||
[#89653]: https://github.com/rust-lang/rust/issues/89653
|
||||
|
||||
------------------------
|
||||
|
||||
The `cfi_encoding` feature allows the user to define a CFI encoding for a type.
|
||||
It allows the user to use a different names for types that otherwise would be
|
||||
required to have the same name as used in externally defined C functions.
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
#![feature(cfi_encoding, extern_types)]
|
||||
|
||||
#[cfi_encoding = "3Foo"]
|
||||
pub struct Type1(i32);
|
||||
|
||||
extern {
|
||||
#[cfi_encoding = "3Bar"]
|
||||
type Type2;
|
||||
}
|
||||
```
|
10
tests/codegen/enable-lto-unit-splitting.rs
Normal file
10
tests/codegen/enable-lto-unit-splitting.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// Verifies that "EnableSplitLTOUnit" module flag is added.
|
||||
//
|
||||
// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo() {
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
|
@ -8,4 +8,4 @@
|
||||
pub fn foo() {
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 2, !"CFI Canonical Jump Tables", i32 1}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 4, !"CFI Canonical Jump Tables", i32 1}
|
||||
|
@ -0,0 +1,11 @@
|
||||
// Verifies that "EnableSplitLTOUnit" module flag is added.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo() {
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
|
@ -0,0 +1,18 @@
|
||||
// Verifies that pointer type membership tests for indirect calls are omitted.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(no_sanitize)]
|
||||
|
||||
#[no_sanitize(cfi)]
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: sanitizer_cfi_emit_type_checks_attr_no_sanitize::foo
|
||||
// CHECK: Function Attrs: {{.*}}
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg)
|
||||
// CHECK-NEXT: ret i32 {{%.+}}
|
||||
f(arg)
|
||||
}
|
@ -6,13 +6,12 @@
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: start:
|
||||
// CHECK: [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"{{[[:print:]]+}}")
|
||||
// CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail
|
||||
// CHECK: type_test.pass:
|
||||
// CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg)
|
||||
// CHECK-NEXT: br label %bb1
|
||||
// CHECK: type_test.fail:
|
||||
// CHECK-NEXT: call void @llvm.trap()
|
||||
// CHECK-NEXT: unreachable
|
||||
|
@ -0,0 +1,48 @@
|
||||
// Verifies that user-defined CFI encoding for types are emitted.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(cfi_encoding, extern_types)]
|
||||
|
||||
#[cfi_encoding = "3Foo"]
|
||||
pub struct Type1(i32);
|
||||
|
||||
extern {
|
||||
#[cfi_encoding = "3Bar"]
|
||||
type Type2;
|
||||
}
|
||||
|
||||
#[cfi_encoding = "3Baz"]
|
||||
#[repr(transparent)]
|
||||
pub struct Type3(i32);
|
||||
|
||||
pub fn foo0(_: Type1) { }
|
||||
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo1(_: Type1, _: Type1) { }
|
||||
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo2(_: Type1, _: Type1, _: Type1) { }
|
||||
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo3(_: *mut Type2) { }
|
||||
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo4(_: *mut Type2, _: *mut Type2) { }
|
||||
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo5(_: *mut Type2, _: *mut Type2, _: *mut Type2) { }
|
||||
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo6(_: *mut Type3) { }
|
||||
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo7(_: *mut Type3, _: *mut Type3) { }
|
||||
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo8(_: *mut Type3, _: *mut Type3, _: *mut Type3) { }
|
||||
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
|
||||
// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFv3FooE"}
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFv3FooS_E"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFv3FooS_S_E"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvP3BarE"}
|
||||
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvP3BarS0_E"}
|
||||
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvP3BarS0_S0_E"}
|
||||
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvP3BazE"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvP3BazS0_E"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvP3BazS0_S0_E"}
|
@ -10,7 +10,7 @@
|
||||
#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)]
|
||||
|
||||
extern crate core;
|
||||
use core::ffi::c_void;
|
||||
use core::ffi::*;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// User-defined type (structure)
|
||||
@ -113,9 +113,10 @@ pub fn fn1<'a>() {
|
||||
let _: Type11 = Quuux;
|
||||
}
|
||||
|
||||
// repr(transparent) user-defined type
|
||||
// Helper type to make Type12 have an unique id
|
||||
struct Foo(i32);
|
||||
|
||||
// repr(transparent) user-defined type
|
||||
#[repr(transparent)]
|
||||
pub struct Type12 {
|
||||
member1: (),
|
||||
@ -131,313 +132,313 @@ pub struct Type13<'a> {
|
||||
member3: &'a Type13<'a>,
|
||||
}
|
||||
|
||||
// Helper type to allow `Type14<Bar>` to be a unique ID
|
||||
// Helper type to make Type14 have an unique id
|
||||
pub struct Bar;
|
||||
|
||||
// repr(transparent) parameterized type
|
||||
// repr(transparent) user-defined generic type
|
||||
#[repr(transparent)]
|
||||
pub struct Type14<T>(T);
|
||||
|
||||
pub fn foo0(_: ()) { }
|
||||
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
|
||||
pub fn foo1(_: c_void, _: ()) { }
|
||||
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo1(_: (), _: c_void) { }
|
||||
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo2(_: (), _: c_void, _: c_void) { }
|
||||
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]]
|
||||
pub fn foo3(_: *mut c_void) { }
|
||||
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]]
|
||||
pub fn foo4(_: *mut c_void, _: *mut ()) { }
|
||||
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo3(_: *mut ()) { }
|
||||
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo4(_: *mut (), _: *mut c_void) { }
|
||||
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { }
|
||||
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]]
|
||||
pub fn foo6(_: *const c_void) { }
|
||||
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]]
|
||||
pub fn foo7(_: *const c_void, _: *const ()) { }
|
||||
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo6(_: *const ()) { }
|
||||
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo7(_: *const (), _: *const c_void) { }
|
||||
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { }
|
||||
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo9(_: bool) { }
|
||||
// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo10(_: bool, _: bool) { }
|
||||
// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo11(_: bool, _: bool, _: bool) { }
|
||||
// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo12(_: i8) { }
|
||||
// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo13(_: i8, _: i8) { }
|
||||
// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo14(_: i8, _: i8, _: i8) { }
|
||||
// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo15(_: i16) { }
|
||||
// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo16(_: i16, _: i16) { }
|
||||
// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo17(_: i16, _: i16, _: i16) { }
|
||||
// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo18(_: i32) { }
|
||||
// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo19(_: i32, _: i32) { }
|
||||
// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo20(_: i32, _: i32, _: i32) { }
|
||||
// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo21(_: i64) { }
|
||||
// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo22(_: i64, _: i64) { }
|
||||
// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo23(_: i64, _: i64, _: i64) { }
|
||||
// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo24(_: i128) { }
|
||||
// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo25(_: i128, _: i128) { }
|
||||
// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo26(_: i128, _: i128, _: i128) { }
|
||||
// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo27(_: isize) { }
|
||||
// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo28(_: isize, _: isize) { }
|
||||
// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo29(_: isize, _: isize, _: isize) { }
|
||||
// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo30(_: u8) { }
|
||||
// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo31(_: u8, _: u8) { }
|
||||
// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo32(_: u8, _: u8, _: u8) { }
|
||||
// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo33(_: u16) { }
|
||||
// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo34(_: u16, _: u16) { }
|
||||
// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo35(_: u16, _: u16, _: u16) { }
|
||||
// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo36(_: u32) { }
|
||||
// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo37(_: u32, _: u32) { }
|
||||
// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo38(_: u32, _: u32, _: u32) { }
|
||||
// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo39(_: u64) { }
|
||||
// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo40(_: u64, _: u64) { }
|
||||
// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo41(_: u64, _: u64, _: u64) { }
|
||||
// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo42(_: u128) { }
|
||||
// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo43(_: u128, _: u128) { }
|
||||
// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo44(_: u128, _: u128, _: u128) { }
|
||||
// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo45(_: usize) { }
|
||||
// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo46(_: usize, _: usize) { }
|
||||
// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo47(_: usize, _: usize, _: usize) { }
|
||||
// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo48(_: f32) { }
|
||||
// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo49(_: f32, _: f32) { }
|
||||
// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo50(_: f32, _: f32, _: f32) { }
|
||||
// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo51(_: f64) { }
|
||||
// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo52(_: f64, _: f64) { }
|
||||
// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo53(_: f64, _: f64, _: f64) { }
|
||||
// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo54(_: char) { }
|
||||
// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo55(_: char, _: char) { }
|
||||
// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo56(_: char, _: char, _: char) { }
|
||||
// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo57(_: &str) { }
|
||||
// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo58(_: &str, _: &str) { }
|
||||
// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo59(_: &str, _: &str, _: &str) { }
|
||||
// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo60(_: (i32, i32)) { }
|
||||
// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo61(_: (i32, i32), _: (i32, i32)) { }
|
||||
// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { }
|
||||
// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo63(_: [i32; 32]) { }
|
||||
// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo64(_: [i32; 32], _: [i32; 32]) { }
|
||||
// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { }
|
||||
// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo66(_: &[i32]) { }
|
||||
// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo67(_: &[i32], _: &[i32]) { }
|
||||
// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { }
|
||||
// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo69(_: &Struct1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo70(_: &Struct1::<i32>, _: &Struct1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo71(_: &Struct1::<i32>, _: &Struct1::<i32>, _: &Struct1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo72(_: &Enum1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo73(_: &Enum1::<i32>, _: &Enum1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo74(_: &Enum1::<i32>, _: &Enum1::<i32>, _: &Enum1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo75(_: &Union1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo76(_: &Union1::<i32>, _: &Union1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo77(_: &Union1::<i32>, _: &Union1::<i32>, _: &Union1::<i32>) { }
|
||||
// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo78(_: *mut type1) { }
|
||||
// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo79(_: *mut type1, _: *mut type1) { }
|
||||
// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { }
|
||||
// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo81(_: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo82(_: &mut i32, _: &i32) { }
|
||||
// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo83(_: &mut i32, _: &i32, _: &i32) { }
|
||||
// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo84(_: &i32) { }
|
||||
// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo85(_: &i32, _: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo87(_: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo88(_: *mut i32, _: *const i32) { }
|
||||
// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { }
|
||||
// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo90(_: *const i32) { }
|
||||
// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo91(_: *const i32, _: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo93(_: fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo96(_: &dyn Fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo99(_: &dyn FnMut(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo102(_: &dyn FnOnce(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { }
|
||||
// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
|
||||
// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo105(_: &dyn Send) { }
|
||||
// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo106(_: &dyn Send, _: &dyn Send) { }
|
||||
// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { }
|
||||
// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo108(_: Type1) { }
|
||||
// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo109(_: Type1, _: Type1) { }
|
||||
// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo110(_: Type1, _: Type1, _: Type1) { }
|
||||
// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo111(_: Type2) { }
|
||||
// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo112(_: Type2, _: Type2) { }
|
||||
// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo113(_: Type2, _: Type2, _: Type2) { }
|
||||
// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo114(_: Type3) { }
|
||||
// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo115(_: Type3, _: Type3) { }
|
||||
// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo116(_: Type3, _: Type3, _: Type3) { }
|
||||
// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo117(_: Type4) { }
|
||||
// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo118(_: Type4, _: Type4) { }
|
||||
// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo119(_: Type4, _: Type4, _: Type4) { }
|
||||
// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo120(_: Type5) { }
|
||||
// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo121(_: Type5, _: Type5) { }
|
||||
// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo122(_: Type5, _: Type5, _: Type5) { }
|
||||
// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo123(_: Type6) { }
|
||||
// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo124(_: Type6, _: Type6) { }
|
||||
// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo125(_: Type6, _: Type6, _: Type6) { }
|
||||
// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo126(_: Type7) { }
|
||||
// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo127(_: Type7, _: Type7) { }
|
||||
// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo128(_: Type7, _: Type7, _: Type7) { }
|
||||
// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo129(_: Type8) { }
|
||||
// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo130(_: Type8, _: Type8) { }
|
||||
// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo131(_: Type8, _: Type8, _: Type8) { }
|
||||
// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo132(_: Type9) { }
|
||||
// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo133(_: Type9, _: Type9) { }
|
||||
// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo134(_: Type9, _: Type9, _: Type9) { }
|
||||
// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo135(_: Type10) { }
|
||||
// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo136(_: Type10, _: Type10) { }
|
||||
// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo137(_: Type10, _: Type10, _: Type10) { }
|
||||
// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo138(_: Type11) { }
|
||||
// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo139(_: Type11, _: Type11) { }
|
||||
// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo140(_: Type11, _: Type11, _: Type11) { }
|
||||
// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo141(_: Type12) { }
|
||||
// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo142(_: Type12, _: Type12) { }
|
||||
// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo143(_: Type12, _: Type12, _: Type12) { }
|
||||
// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo144(_: Type13) { }
|
||||
// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo145(_: Type13, _: Type13) { }
|
||||
// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo146(_: Type13, _: Type13, _: Type13) { }
|
||||
// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo147(_: Type14<Bar>) { }
|
||||
// CHECK: define{{.*}}foo147{{.*}}!type ![[TYPE147:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo147{{.*}}!type ![[TYPE147:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo148(_: Type14<Bar>, _: Type14<Bar>) { }
|
||||
// CHECK: define{{.*}}foo148{{.*}}!type ![[TYPE148:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo148{{.*}}!type ![[TYPE148:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
|
||||
// CHECK: define{{.*}}foo149{{.*}}!type ![[TYPE149:[0-9]+]]
|
||||
// CHECK: define{{.*}}foo149{{.*}}!type ![[TYPE149:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
|
||||
// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
|
||||
|
@ -0,0 +1,31 @@
|
||||
// Verifies that generalized type metadata for functions are emitted.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized")
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized")
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized")
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.generalized"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.generalized"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.generalized"}
|
@ -0,0 +1,31 @@
|
||||
// Verifies that normalized and generalized type metadata for functions are emitted.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo
|
||||
// CHECK-SAME: {{.*}}![[TYPE1:[0-9]+]]
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized")
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}![[TYPE2:[0-9]+]]
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized")
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}![[TYPE3:[0-9]+]]
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized")
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.normalized.generalized"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.normalized.generalized"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.normalized.generalized"}
|
@ -0,0 +1,31 @@
|
||||
// Verifies that normalized type metadata for functions are emitted.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized")
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized")
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized")
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E.normalized"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E.normalized"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E.normalized"}
|
@ -7,21 +7,21 @@
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]]
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_E")
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]]
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E")
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]]
|
||||
// CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E")
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
46
tests/codegen/sanitizer-cfi-generalize-pointers.rs
Normal file
46
tests/codegen/sanitizer-cfi-generalize-pointers.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// Verifies that pointer types are generalized.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
extern crate core;
|
||||
|
||||
pub fn foo0(_: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo1(_: &mut i32, _: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo2(_: &mut i32, _: &mut i32, _: &mut i32) { }
|
||||
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo3(_: &i32) { }
|
||||
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo4(_: &i32, _: &i32) { }
|
||||
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo5(_: &i32, _: &i32, _: &i32) { }
|
||||
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo6(_: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo7(_: *mut i32, _: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo8(_: *mut i32, _: *mut i32, _: *mut i32) { }
|
||||
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo9(_: *const i32) { }
|
||||
// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo10(_: *const i32, _: *const i32) { }
|
||||
// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo11(_: *const i32, _: *const i32, _: *const i32) { }
|
||||
// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
|
||||
// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvU3mutu3refIvEE.generalized"}
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_E.generalized"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_S0_E.generalized"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIvEE.generalized"}
|
||||
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvES_E.generalized"}
|
||||
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_S_E.generalized"}
|
||||
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvE.generalized"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPvS_E.generalized"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPvS_S_E.generalized"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
|
||||
// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKvS0_E.generalized"}
|
||||
// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKvS0_S0_E.generalized"}
|
83
tests/codegen/sanitizer-cfi-normalize-integers.rs
Normal file
83
tests/codegen/sanitizer-cfi-normalize-integers.rs
Normal file
@ -0,0 +1,83 @@
|
||||
// Verifies that integer types are normalized.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
extern crate core;
|
||||
use core::ffi::*;
|
||||
|
||||
pub fn foo0(_: bool) { }
|
||||
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo1(_: bool, _: c_uchar) { }
|
||||
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo2(_: bool, _: c_uchar, _: c_uchar) { }
|
||||
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo3(_: isize) { }
|
||||
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo4(_: isize, _: c_long) { }
|
||||
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo5(_: isize, _: c_long, _: c_longlong) { }
|
||||
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo6(_: usize) { }
|
||||
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo7(_: usize, _: c_ulong) { }
|
||||
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo8(_: usize, _: c_ulong, _: c_ulonglong) { }
|
||||
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo9(_: c_schar) { }
|
||||
// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo10(_: c_char, _: c_schar) { }
|
||||
// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo11(_: c_char, _: c_schar, _: c_schar) { }
|
||||
// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo12(_: c_int) { }
|
||||
// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo13(_: c_int, _: c_int) { }
|
||||
// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo14(_: c_int, _: c_int, _: c_int) { }
|
||||
// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo15(_: c_short) { }
|
||||
// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo16(_: c_short, _: c_short) { }
|
||||
// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo17(_: c_short, _: c_short, _: c_short) { }
|
||||
// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo18(_: c_uint) { }
|
||||
// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo19(_: c_uint, _: c_uint) { }
|
||||
// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo20(_: c_uint, _: c_uint, _: c_uint) { }
|
||||
// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo21(_: c_ushort) { }
|
||||
// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo22(_: c_ushort, _: c_ushort) { }
|
||||
// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}}
|
||||
pub fn foo23(_: c_ushort, _: c_ushort, _: c_ushort) { }
|
||||
// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}}
|
||||
|
||||
// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"}
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"}
|
||||
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"}
|
||||
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}E.normalized"}
|
||||
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}{{u3i32|u3i64|S_}}E.normalized"}
|
||||
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}{{u3i32|u3i64|S_}}{{u3i64|S_|S0_}}E.normalized"}
|
||||
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}E.normalized"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}{{u3u32|u3u64|S_}}E.normalized"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}{{u3u32|u3u64|S_}}{{u3u64|S_|S0_}}E.normalized"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu2i8E.normalized"}
|
||||
// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u2i8S_|u2u8u2i8}}E.normalized"}
|
||||
// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u2i8S_S_|u2u8u2i8S0_}}E.normalized"}
|
||||
// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}E.normalized"}
|
||||
// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}S_E.normalized"}
|
||||
// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}S_S_E.normalized"}
|
||||
// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E.normalized"}
|
||||
// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E.normalized"}
|
||||
// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E.normalized"}
|
||||
// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}E.normalized"}
|
||||
// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}S_E.normalized"}
|
||||
// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}S_S_E.normalized"}
|
||||
// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3u16E.normalized"}
|
||||
// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3u16S_E.normalized"}
|
||||
// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3u16S_S_E.normalized"}
|
@ -0,0 +1,30 @@
|
||||
// Verifies that KCFI operand bundles are omitted.
|
||||
//
|
||||
// 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 -Copt-level=0
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(no_core, no_sanitize, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang="sized"]
|
||||
trait Sized { }
|
||||
#[lang="copy"]
|
||||
trait Copy { }
|
||||
|
||||
impl Copy for i32 {}
|
||||
|
||||
#[no_sanitize(kcfi)]
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: sanitizer_kcfi_emit_kcfi_operand_bundle_attr_no_sanitize::foo
|
||||
// CHECK: Function Attrs: {{.*}}
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ]
|
||||
// CHECK: ret i32 {{%.+}}
|
||||
f(arg)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// Verifies that generalized 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 -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![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
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 233085384) ]
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 435418021) ]
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1003721339) ]
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i32 -1741689296}
|
||||
// CHECK: ![[TYPE2]] = !{i32 489439372}
|
||||
// CHECK: ![[TYPE3]] = !{i32 2026563871}
|
@ -0,0 +1,44 @@
|
||||
// Verifies that normalized and generalized 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 -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![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
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -686570305) ]
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1281038450) ]
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1751512973) ]
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i32 975484707}
|
||||
// CHECK: ![[TYPE2]] = !{i32 1658833102}
|
||||
// CHECK: ![[TYPE3]] = !{i32 230429758}
|
@ -0,0 +1,44 @@
|
||||
// Verifies that normalized 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 -Zsanitizer-cfi-normalize-integers
|
||||
|
||||
#![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
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -841055669) ]
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1390819368) ]
|
||||
f(arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}baz
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 586925835) ]
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i32 -458317079}
|
||||
// CHECK: ![[TYPE2]] = !{i32 1737138182}
|
||||
// CHECK: ![[TYPE3]] = !{i32 197182412}
|
@ -20,22 +20,22 @@ impl Copy for i32 {}
|
||||
|
||||
pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}foo
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
|
||||
// CHECK: call i32 %f(i32 %arg){{.*}}[ "kcfi"(i32 -1666898348) ]
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE1:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -1666898348) ]
|
||||
f(arg)
|
||||
}
|
||||
|
||||
pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
|
||||
// CHECK-LABEL: define{{.*}}bar
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
|
||||
// CHECK: call i32 %f(i32 %arg1, i32 %arg2){{.*}}[ "kcfi"(i32 -1789026986) ]
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE2:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%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
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
|
||||
// CHECK: call i32 %f(i32 %arg1, i32 %arg2, i32 %arg3){{.*}}[ "kcfi"(i32 1248878270) ]
|
||||
// CHECK-SAME: {{.*}}!{{<unknown kind #36>|kcfi_type}} ![[TYPE3:[0-9]+]]
|
||||
// CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 1248878270) ]
|
||||
f(arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
|
27
tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs
Normal file
27
tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Verifies that KCFI operand bundles 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 -Copt-level=0
|
||||
|
||||
#![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{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ]
|
||||
// CHECK-NEXT: ret i32 {{%.+}}
|
||||
f(arg)
|
||||
}
|
11
tests/codegen/split-lto-unit.rs
Normal file
11
tests/codegen/split-lto-unit.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// Verifies that "EnableSplitLTOUnit" module flag is added.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
pub fn foo() {
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
|
4
tests/ui/feature-gates/feature-gate-cfi_encoding.rs
Normal file
4
tests/ui/feature-gates/feature-gate-cfi_encoding.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[cfi_encoding = "3Bar"] //~ERROR 3:1: 3:25: the `#[cfi_encoding]` attribute is an experimental feature [E0658]
|
||||
pub struct Foo(i32);
|
12
tests/ui/feature-gates/feature-gate-cfi_encoding.stderr
Normal file
12
tests/ui/feature-gates/feature-gate-cfi_encoding.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0658]: the `#[cfi_encoding]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-cfi_encoding.rs:3:1
|
||||
|
|
||||
LL | #[cfi_encoding = "3Bar"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #89653 <https://github.com/rust-lang/rust/issues/89653> for more information
|
||||
= help: add `#![feature(cfi_encoding)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -3,12 +3,16 @@
|
||||
|
||||
// needs-sanitizer-support
|
||||
// needs-sanitizer-address
|
||||
// needs-sanitizer-cfi
|
||||
// needs-sanitizer-kcfi
|
||||
// needs-sanitizer-leak
|
||||
// needs-sanitizer-memory
|
||||
// needs-sanitizer-thread
|
||||
// check-pass
|
||||
// revisions: address leak memory thread
|
||||
//[address]compile-flags: -Zsanitizer=address --cfg address
|
||||
//[cfi]compile-flags: -Zsanitizer=cfi --cfg cfi
|
||||
//[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi
|
||||
//[leak]compile-flags: -Zsanitizer=leak --cfg leak
|
||||
//[memory]compile-flags: -Zsanitizer=memory --cfg memory
|
||||
//[thread]compile-flags: -Zsanitizer=thread --cfg thread
|
||||
@ -18,6 +22,12 @@
|
||||
#[cfg(all(sanitize = "address", address))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(all(sanitize = "cfi", cfi))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(all(sanitize = "kcfi", kcfi))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(all(sanitize = "leak", leak))]
|
||||
fn main() {}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
// Verifies that `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer-cfi-canonical-jump-tables=false
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
@ -0,0 +1,4 @@
|
||||
error: `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,9 @@
|
||||
// Verifies that when compiling with `-Zsanitizer-cfi-generalize-pointers` the
|
||||
// `#[cfg(sanitizer_cfi_generalize_pointers)]` attribute is configured.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// check-pass
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#[cfg(sanitizer_cfi_generalize_pointers)]
|
||||
fn main() {}
|
@ -0,0 +1,9 @@
|
||||
// Verifies that `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or
|
||||
// `-Zsanitizer=kcfi`.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer-cfi-generalize-pointers
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
@ -0,0 +1,4 @@
|
||||
error: `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
11
tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.rs
Normal file
11
tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// Verifies that invalid user-defined CFI encodings can't be used.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
|
||||
|
||||
#![feature(cfi_encoding, no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
||||
|
||||
#[cfi_encoding] //~ERROR 10:1: 10:16: malformed `cfi_encoding` attribute input
|
||||
pub struct Type1(i32);
|
@ -0,0 +1,8 @@
|
||||
error: malformed `cfi_encoding` attribute input
|
||||
--> $DIR/sanitizer-cfi-invalid-attr-cfi-encoding.rs:10:1
|
||||
|
|
||||
LL | #[cfi_encoding]
|
||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,8 @@
|
||||
error: cfi sanitizer is not supported for this target
|
||||
|
||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
||||
|
||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -0,0 +1,12 @@
|
||||
// Verifies that `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`.
|
||||
//
|
||||
// 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: x86
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer=kcfi
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
@ -0,0 +1,8 @@
|
||||
error: cfi sanitizer is not supported for this target
|
||||
|
||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
||||
|
||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -0,0 +1,9 @@
|
||||
// Verifies that when compiling with `-Zsanitizer-cfi-normalize-integers` the
|
||||
// `#[cfg(sanitizer_cfi_normalize_integers)]` attribute is configured.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// check-pass
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
|
||||
|
||||
#[cfg(sanitizer_cfi_normalize_integers)]
|
||||
fn main() {}
|
@ -0,0 +1,9 @@
|
||||
// Verifies that `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or
|
||||
// `-Zsanitizer=kcfi`
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer-cfi-normalize-integers
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
@ -0,0 +1,4 @@
|
||||
error: `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
8
tests/ui/sanitize/sanitizer-cfi-requires-lto.rs
Normal file
8
tests/ui/sanitize/sanitizer-cfi-requires-lto.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Verifies that `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
4
tests/ui/sanitize/sanitizer-cfi-requires-lto.stderr
Normal file
4
tests/ui/sanitize/sanitizer-cfi-requires-lto.stderr
Normal file
@ -0,0 +1,4 @@
|
||||
error: `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
8
tests/ui/sanitize/split-lto-unit-requires-lto.rs
Normal file
8
tests/ui/sanitize/split-lto-unit-requires-lto.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Verifies that `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsplit-lto-unit
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![no_main]
|
4
tests/ui/sanitize/split-lto-unit-requires-lto.stderr
Normal file
4
tests/ui/sanitize/split-lto-unit-requires-lto.stderr
Normal file
@ -0,0 +1,4 @@
|
||||
error: `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user