Skip to content

Commit 95cf939

Browse files
committed
Report error when using naked functions with arguments
As mentioned in issue: rust-lang#42779 a naked function with arguments will cause LLVM to generate some prologue code for the arguments. This goes against the idea of a naked function and can cause difficult to diagnose bugs. The current situation is wrong and leaves users exposed to nasty bugs. There are two possible solutions: 1. Not allow any naked functions to have arguments. This is the method taken by this patch. 2. Modify LLVM to not generate any prologue code for naked functions. This seems like a more controversial change as it will impact all LLVM users and I am not sure how other languages will handle this. It seems unlikely that there are many naked functions that don't call inline assembly as the first or only code in the function. In which case the inline assembly can assess the registers used to pass arguments still allowing arguments to be passed to naked functions. Rust shouldn't be calling naked functions [1] so this is unlikely to be a major concern. 1: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md "Because the calling convention of a naked function is not guaranteed to match any calling convention the compiler is compatible with, calls to naked functions from within Rust code are forbidden unless the function is also declared with a well-defined ABI." Signed-off-by: Alistair Francis <[email protected]>
1 parent a37fe2d commit 95cf939

File tree

5 files changed

+56
-66
lines changed

5 files changed

+56
-66
lines changed

src/librustc_typeck/collect.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2587,7 +2587,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
25872587
} else if attr.check_name(sym::rustc_allocator_nounwind) {
25882588
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
25892589
} else if attr.check_name(sym::naked) {
2590-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
2590+
if tcx.fn_sig(id).inputs().skip_binder().iter().len() == 0 {
2591+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
2592+
} else {
2593+
struct_span_err!(
2594+
tcx.sess,
2595+
attr.span,
2596+
E0051,
2597+
"unable to use `naked` on function with inputs"
2598+
).emit();
2599+
}
25912600
} else if attr.check_name(sym::no_mangle) {
25922601
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
25932602
} else if attr.check_name(sym::rustc_std_internal_symbol) {

src/librustc_typeck/error_codes.rs

+25
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,31 @@ impl Foo for Bar {
465465
```
466466
"##,
467467

468+
E0051: r##"
469+
This error indicates that an attempted implementation of a naked function
470+
has arguments and naked functions cannot have any arguments.
471+
472+
A naked function with arguments will still have some code generated by the
473+
compiller to push the functions onto the stack.
474+
475+
```compile_fail,E0051
476+
#[naked]
477+
#[no_mangle]
478+
#[inline(never)]
479+
pub extern "C" fn naked_test(_fubar: u64) {
480+
unsafe { asm!("int3") }
481+
}
482+
483+
// Will generate the following assembly, which is not naked
484+
// naked_test:
485+
// movq %rdi, (%rsp)
486+
// #APP
487+
// int3
488+
// #NO_APP
489+
// retq
490+
```
491+
"##,
492+
468493
E0053: r##"
469494
The parameters of any trait method must match between a trait implementation
470495
and the trait definition.

src/test/codegen/naked-functions.rs

-65
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// ignore-tidy-linelength
2-
31
// compile-flags: -C no-prepopulate-passes
42

53
#![crate_type = "lib"]
@@ -14,17 +12,6 @@ pub fn naked_empty() {
1412
// CHECK-NEXT: ret void
1513
}
1614

17-
// CHECK: Function Attrs: naked
18-
#[no_mangle]
19-
#[naked]
20-
// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
21-
pub fn naked_with_args(a: isize) {
22-
// CHECK-NEXT: {{.+}}:
23-
// CHECK-NEXT: %a = alloca i{{[0-9]+}}
24-
&a; // keep variable in an alloca
25-
// CHECK: ret void
26-
}
27-
2815
// CHECK: Function Attrs: naked
2916
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_return()
3017
#[no_mangle]
@@ -34,55 +21,3 @@ pub fn naked_with_return() -> isize {
3421
// CHECK-NEXT: ret i{{[0-9]+}} 0
3522
0
3623
}
37-
38-
// CHECK: Function Attrs: naked
39-
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
40-
#[no_mangle]
41-
#[naked]
42-
pub fn naked_with_args_and_return(a: isize) -> isize {
43-
// CHECK-NEXT: {{.+}}:
44-
// CHECK-NEXT: %a = alloca i{{[0-9]+}}
45-
&a; // keep variable in an alloca
46-
// CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
47-
a
48-
}
49-
50-
// CHECK: Function Attrs: naked
51-
// CHECK-NEXT: define void @naked_recursive()
52-
#[no_mangle]
53-
#[naked]
54-
pub fn naked_recursive() {
55-
// CHECK-NEXT: {{.+}}:
56-
// CHECK-NEXT: call void @naked_empty()
57-
58-
// FIXME(#39685) Avoid one block per call.
59-
// CHECK-NEXT: br label %bb1
60-
// CHECK: bb1:
61-
62-
naked_empty();
63-
64-
// CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return()
65-
66-
// FIXME(#39685) Avoid one block per call.
67-
// CHECK-NEXT: br label %bb2
68-
// CHECK: bb2:
69-
70-
// CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}})
71-
72-
// FIXME(#39685) Avoid one block per call.
73-
// CHECK-NEXT: br label %bb3
74-
// CHECK: bb3:
75-
76-
// CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}})
77-
78-
// FIXME(#39685) Avoid one block per call.
79-
// CHECK-NEXT: br label %bb4
80-
// CHECK: bb4:
81-
82-
naked_with_args(
83-
naked_with_args_and_return(
84-
naked_with_return()
85-
)
86-
);
87-
// CHECK-NEXT: ret void
88-
}

src/test/ui/error-codes/E0051.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(asm, naked_functions)]
2+
3+
#[naked] //~ ERROR E0051
4+
#[no_mangle]
5+
#[inline(never)]
6+
pub extern "C" fn naked_test(_fubar: u64) {
7+
unsafe { asm!("int3") }
8+
}
9+
10+
pub fn main() {
11+
naked_test(1);
12+
}

src/test/ui/error-codes/E0051.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0051]: unable to use `naked` on function with inputs
2+
--> $DIR/E0051.rs:3:1
3+
|
4+
LL | #[naked]
5+
| ^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0051`.

0 commit comments

Comments
 (0)