fix -Zsanitizer=kcfi on #[naked] functions

And more broadly only codegen `InstanceKind::Item` using the naked
function codegen code. Other instance kinds should follow the normal
path.
This commit is contained in:
Folkert de Vries 2025-07-01 20:02:31 +02:00
parent 9c3064e131
commit f100767dce
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 91 additions and 8 deletions

View file

@ -530,8 +530,12 @@ fn codegen_cgu_content(
for (mono_item, item_data) in mono_items {
match mono_item {
MonoItem::Fn(instance) => {
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
{
// Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be
// codegened like a normal function.
let is_item_instance = matches!(instance.def, InstanceKind::Item(_));
let flags = tcx.codegen_fn_attrs(instance.def_id()).flags;
if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) {
rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
&mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
instance,

View file

@ -1,5 +1,6 @@
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
use rustc_middle::ty::InstanceKind;
use rustc_middle::ty::layout::HasTyCtxt;
use tracing::debug;
@ -41,12 +42,12 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
base::codegen_global_asm(cx, item_id);
}
MonoItem::Fn(instance) => {
if cx
.tcx()
.codegen_fn_attrs(instance.def_id())
.flags
.contains(CodegenFnAttrFlags::NAKED)
{
// Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be
// codegened like a normal function.
let is_item_instance = matches!(instance.def, InstanceKind::Item(_));
let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) {
naked_asm::codegen_naked_asm::<Bx::CodegenCx>(cx, instance, item_data);
} else {
base::codegen_instance::<Bx>(cx, instance);

View file

@ -0,0 +1,47 @@
//@ add-core-stubs
//@ 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: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0
#![feature(no_core, lang_items)]
#![crate_type = "lib"]
#![no_core]
extern crate minicore;
use minicore::*;
struct Thing;
trait MyTrait {
#[unsafe(naked)]
extern "C" fn my_naked_function() {
// the real function is defined
// CHECK: .globl
// CHECK-SAME: my_naked_function
naked_asm!("ret")
}
}
impl MyTrait for Thing {}
// CHECK-LABEL: main
#[unsafe(no_mangle)]
pub fn main() {
// Trick the compiler into generating an indirect call.
const F: extern "C" fn() = Thing::my_naked_function;
// main calls the shim function
// CHECK: call
// CHECK-SAME: my_naked_function
// CHECK-SAME: reify.shim.fnptr
(F)();
}
// the shim calls the real function
// CHECK: define
// CHECK-SAME: my_naked_function
// CHECK-SAME: reify.shim.fnptr
// CHECK: declare !kcfi_type
// CHECK-SAME: my_naked_function

View file

@ -0,0 +1,31 @@
// The indirect call will generate a shim that then calls the actual function. Test that
// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266.
//@ build-pass
//@ add-core-stubs
//@ 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
#![feature(no_core, lang_items)]
#![crate_type = "lib"]
#![no_core]
extern crate minicore;
use minicore::*;
trait MyTrait {
#[unsafe(naked)]
extern "C" fn foo(&self) {
naked_asm!("ret")
}
}
impl MyTrait for i32 {}
fn main() {
let x: extern "C" fn(&_) = <dyn MyTrait as MyTrait>::foo;
x(&1);
}