use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
}
- let fn_ptr = match (llfn, instance) {
- (Some(llfn), _) => llfn,
- (None, Some(instance)) => bx.get_fn_addr(instance),
+ 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"),
};
+ // 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 = bx.typeid_metadata(typeid);
+
+ // Test whether the function pointer is associated with the type identifier.
+ let cond = bx.type_test(fn_ptr, typeid_metadata);
+ let mut bx_pass = bx.build_sibling_block("type_test.pass");
+ let mut bx_fail = bx.build_sibling_block("type_test.fail");
+ bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+ helper.do_call(
+ self,
+ &mut bx_pass,
+ fn_abi,
+ fn_ptr,
+ &llargs,
+ destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+ cleanup,
+ );
+
+ bx_fail.abort();
+ bx_fail.unreachable();
+
+ return;
+ }
+
helper.do_call(
self,
&mut bx,
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
) {
let span = terminator.source_info.span;
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans);
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
if let Some(target) = destination {
helper.funclet_br(self, &mut bx, target);
}
mir::TerminatorKind::Goto { target } => {
- if bb == target {
- // This is an unconditional branch back to this same basic block. That means we
- // have something like a `loop {}` statement. LLVM versions before 12.0
- // miscompile this because they assume forward progress. For older versions
- // try to handle just this specific case which comes up commonly in practice
- // (e.g., in embedded code).
- //
- // NB: the `sideeffect` currently checks for the LLVM version used internally.
- bx.sideeffect();
- }
-
helper.funclet_br(self, &mut bx, target);
}
options,
line_spans,
destination,
+ self.instance,
);
}
}