Skip to content

Commit

Permalink
Report error when using naked functions with arguments
Browse files Browse the repository at this point in the history
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 <alistair.francis@wdc.com>
  • Loading branch information
alistair23 committed Sep 27, 2019
1 parent a37fe2d commit 95cf939
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 66 deletions.
11 changes: 10 additions & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2587,7 +2587,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.check_name(sym::rustc_allocator_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
} else if attr.check_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
if tcx.fn_sig(id).inputs().skip_binder().iter().len() == 0 {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
} else {
struct_span_err!(
tcx.sess,
attr.span,
E0051,
"unable to use `naked` on function with inputs"
).emit();
}
} else if attr.check_name(sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else if attr.check_name(sym::rustc_std_internal_symbol) {
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_typeck/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,31 @@ impl Foo for Bar {
```
"##,

E0051: r##"
This error indicates that an attempted implementation of a naked function
has arguments and naked functions cannot have any arguments.
A naked function with arguments will still have some code generated by the
compiller to push the functions onto the stack.
```compile_fail,E0051
#[naked]
#[no_mangle]
#[inline(never)]
pub extern "C" fn naked_test(_fubar: u64) {
unsafe { asm!("int3") }
}
// Will generate the following assembly, which is not naked
// naked_test:
// movq %rdi, (%rsp)
// #APP
// int3
// #NO_APP
// retq
```
"##,

E0053: r##"
The parameters of any trait method must match between a trait implementation
and the trait definition.
Expand Down
65 changes: 0 additions & 65 deletions src/test/codegen/naked-functions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore-tidy-linelength

// compile-flags: -C no-prepopulate-passes

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

// CHECK: Function Attrs: naked
#[no_mangle]
#[naked]
// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
pub fn naked_with_args(a: isize) {
// CHECK-NEXT: {{.+}}:
// CHECK-NEXT: %a = alloca i{{[0-9]+}}
&a; // keep variable in an alloca
// CHECK: ret void
}

// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_return()
#[no_mangle]
Expand All @@ -34,55 +21,3 @@ pub fn naked_with_return() -> isize {
// CHECK-NEXT: ret i{{[0-9]+}} 0
0
}

// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
#[no_mangle]
#[naked]
pub fn naked_with_args_and_return(a: isize) -> isize {
// CHECK-NEXT: {{.+}}:
// CHECK-NEXT: %a = alloca i{{[0-9]+}}
&a; // keep variable in an alloca
// CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
a
}

// CHECK: Function Attrs: naked
// CHECK-NEXT: define void @naked_recursive()
#[no_mangle]
#[naked]
pub fn naked_recursive() {
// CHECK-NEXT: {{.+}}:
// CHECK-NEXT: call void @naked_empty()

// FIXME(#39685) Avoid one block per call.
// CHECK-NEXT: br label %bb1
// CHECK: bb1:

naked_empty();

// CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return()

// FIXME(#39685) Avoid one block per call.
// CHECK-NEXT: br label %bb2
// CHECK: bb2:

// CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}})

// FIXME(#39685) Avoid one block per call.
// CHECK-NEXT: br label %bb3
// CHECK: bb3:

// CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}})

// FIXME(#39685) Avoid one block per call.
// CHECK-NEXT: br label %bb4
// CHECK: bb4:

naked_with_args(
naked_with_args_and_return(
naked_with_return()
)
);
// CHECK-NEXT: ret void
}
12 changes: 12 additions & 0 deletions src/test/ui/error-codes/E0051.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![feature(asm, naked_functions)]

#[naked] //~ ERROR E0051
#[no_mangle]
#[inline(never)]
pub extern "C" fn naked_test(_fubar: u64) {
unsafe { asm!("int3") }
}

pub fn main() {
naked_test(1);
}
9 changes: 9 additions & 0 deletions src/test/ui/error-codes/E0051.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0051]: unable to use `naked` on function with inputs
--> $DIR/E0051.rs:3:1
|
LL | #[naked]
| ^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0051`.

0 comments on commit 95cf939

Please sign in to comment.