Skip to content

Commit 41dfac0

Browse files
committed
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.
1 parent f46ce66 commit 41dfac0

File tree

4 files changed

+91
-8
lines changed

4 files changed

+91
-8
lines changed

compiler/rustc_codegen_cranelift/src/driver/aot.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,12 @@ fn codegen_cgu_content(
530530
for (mono_item, item_data) in mono_items {
531531
match mono_item {
532532
MonoItem::Fn(instance) => {
533-
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
534-
{
533+
// Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be
534+
// codegened like a normal function.
535+
let is_item_instance = matches!(instance.def, InstanceKind::Item(_));
536+
537+
let flags = tcx.codegen_fn_attrs(instance.def_id()).flags;
538+
if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) {
535539
rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
536540
&mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
537541
instance,

compiler/rustc_codegen_ssa/src/mono_item.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
22
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
3+
use rustc_middle::ty::InstanceKind;
34
use rustc_middle::ty::layout::HasTyCtxt;
45
use tracing::debug;
56

@@ -41,12 +42,12 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
4142
base::codegen_global_asm(cx, item_id);
4243
}
4344
MonoItem::Fn(instance) => {
44-
if cx
45-
.tcx()
46-
.codegen_fn_attrs(instance.def_id())
47-
.flags
48-
.contains(CodegenFnAttrFlags::NAKED)
49-
{
45+
// Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be
46+
// codegened like a normal function.
47+
let is_item_instance = matches!(instance.def, InstanceKind::Item(_));
48+
49+
let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
50+
if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) {
5051
naked_asm::codegen_naked_asm::<Bx::CodegenCx>(cx, instance, item_data);
5152
} else {
5253
base::codegen_instance::<Bx>(cx, instance);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//@ add-core-stubs
2+
//@ revisions: aarch64 x86_64
3+
//@ [aarch64] compile-flags: --target aarch64-unknown-none
4+
//@ [aarch64] needs-llvm-components: aarch64
5+
//@ [x86_64] compile-flags: --target x86_64-unknown-none
6+
//@ [x86_64] needs-llvm-components: x86
7+
//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0
8+
9+
#![feature(no_core, lang_items)]
10+
#![crate_type = "lib"]
11+
#![no_core]
12+
13+
extern crate minicore;
14+
use minicore::*;
15+
16+
struct Thing;
17+
trait MyTrait {
18+
#[unsafe(naked)]
19+
extern "C" fn my_naked_function() {
20+
// the real function is defined
21+
// CHECK: .globl
22+
// CHECK-SAME: my_naked_function
23+
naked_asm!("ret")
24+
}
25+
}
26+
impl MyTrait for Thing {}
27+
28+
// CHECK-LABEL: main
29+
#[unsafe(no_mangle)]
30+
pub fn main() {
31+
// Trick the compiler into generating an indirect call.
32+
const F: extern "C" fn() = Thing::my_naked_function;
33+
34+
// main calls the shim function
35+
// CHECK: call
36+
// CHECK-SAME: my_naked_function
37+
// CHECK-SAME: reify.shim.fnptr
38+
(F)();
39+
}
40+
41+
// the shim calls the real function
42+
// CHECK: define
43+
// CHECK-SAME: my_naked_function
44+
// CHECK-SAME: reify.shim.fnptr
45+
46+
// CHECK: declare !kcfi_type
47+
// CHECK-SAME: my_naked_function

tests/ui/asm/naked-function-shim.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// The indirect call will generate a shim that then calls the actual function. Test that
2+
// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266.
3+
4+
//@ build-pass
5+
//@ add-core-stubs
6+
//@ revisions: aarch64 x86_64
7+
//@ [aarch64] compile-flags: --target aarch64-unknown-none
8+
//@ [aarch64] needs-llvm-components: aarch64
9+
//@ [x86_64] compile-flags: --target x86_64-unknown-none
10+
//@ [x86_64] needs-llvm-components: x86
11+
12+
#![feature(no_core, lang_items)]
13+
#![crate_type = "lib"]
14+
#![no_core]
15+
16+
extern crate minicore;
17+
use minicore::*;
18+
19+
trait MyTrait {
20+
#[unsafe(naked)]
21+
extern "C" fn foo(&self) {
22+
naked_asm!("ret")
23+
}
24+
}
25+
26+
impl MyTrait for i32 {}
27+
28+
fn main() {
29+
let x: extern "C" fn(&_) = <dyn MyTrait as MyTrait>::foo;
30+
x(&1);
31+
}

0 commit comments

Comments
 (0)