From 0356bb9fbba55f0a8fbe38731d41f57048f2e00b Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Tue, 11 Aug 2020 14:07:08 -0400 Subject: [PATCH 1/2] Revert "Suppress debuginfo on naked function arguments" This reverts commit 25670749b44a9c7a4cfd3fbf780bbe3344a9a6c5. This commit does not actually fix the problem. It merely removes the name of the argument from the LLVM output. Even without the name, Rust codegen still spills the (nameless) variable onto the stack which is the root cause. The root cause is solved in the next commit. --- src/librustc_mir_build/build/mod.rs | 12 +----- src/test/codegen/naked-functions.rs | 4 +- .../debuginfo/function-arguments-naked.rs | 42 ------------------- 3 files changed, 3 insertions(+), 55 deletions(-) delete mode 100644 src/test/debuginfo/function-arguments-naked.rs diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index f3f3c3e33a46d..215a0c7dfdf27 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -10,7 +10,6 @@ use rustc_hir::lang_items; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; @@ -798,22 +797,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { argument_scope: region::Scope, ast_body: &'tcx hir::Expr<'tcx>, ) -> BlockAnd<()> { - let tcx = self.hir.tcx(); - let attrs = tcx.codegen_fn_attrs(fn_def_id); - let naked = attrs.flags.contains(CodegenFnAttrFlags::NAKED); - // Allocate locals for the function arguments for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { let source_info = SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span)); let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info)); - // Emit function argument debuginfo only for non-naked functions. - // See: https://github.com/rust-lang/rust/issues/42779 - if naked { - continue; - } - // If this is a simple binding pattern, give debuginfo a nice name. if let Some(arg) = arg_opt { if let Some(ident) = arg.pat.simple_ident() { @@ -826,6 +815,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + let tcx = self.hir.tcx(); let tcx_hir = tcx.hir(); let hir_typeck_results = self.hir.typeck_results(); diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 758c6c4da9293..493c1b9f0ba6b 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -18,7 +18,7 @@ pub fn naked_empty() { // CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}}) pub fn naked_with_args(a: isize) { // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: %_1 = alloca i{{[0-9]+}} + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca // CHECK: ret void } @@ -39,7 +39,7 @@ pub fn naked_with_return() -> isize { #[naked] pub fn naked_with_args_and_return(a: isize) -> isize { // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: %_1 = alloca i{{[0-9]+}} + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a diff --git a/src/test/debuginfo/function-arguments-naked.rs b/src/test/debuginfo/function-arguments-naked.rs deleted file mode 100644 index 5f3a1eb44e4e5..0000000000000 --- a/src/test/debuginfo/function-arguments-naked.rs +++ /dev/null @@ -1,42 +0,0 @@ -// min-lldb-version: 310 - -// We have to ignore android because of this issue: -// https://github.com/rust-lang/rust/issues/74847 -// ignore-android -// -// We need to use inline assembly, so just use one platform -// only-x86_64 - -// compile-flags:-g - -// === GDB TESTS =================================================================================== - -// gdb-command:run - -// gdb-command:info args -// gdb-check:No arguments. -// gdb-command:continue - -// === LLDB TESTS ================================================================================== - -// lldb-command:run - -// lldb-command:frame variable -// lldbg-check:(unsigned long) = 111 (unsigned long) = 222 -// lldbr-check:(unsigned long) = 111 (unsigned long) = 222 -// lldb-command:continue - - -#![feature(asm)] -#![feature(naked_functions)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] - -fn main() { - naked(111, 222); -} - -#[naked] -extern "C" fn naked(x: usize, y: usize) { - unsafe { asm!("ret"); } // #break -} From 050fb380aaa5f95ca27d6365cea06ea614c4cbf7 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Tue, 11 Aug 2020 14:09:39 -0400 Subject: [PATCH 2/2] Don't spill operands onto the stack in naked functions Currently, the code spills operands onto the stack for the purpose of debuginfo. However, naked functions can only contain an asm block. Therefore, attempting to spill the operands on the stack is undefined behavior. Fixes https://github.com/rust-lang/rust/issues/42779 cc https://github.com/rust-lang/rust/issues/32408 --- src/librustc_codegen_ssa/mir/debuginfo.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index d166a27b5a982..d8a530d98faa7 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -1,6 +1,7 @@ use crate::traits::*; use rustc_hir::def_id::CrateNum; use rustc_index::vec::IndexVec; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; use rustc_session::config::DebugInfo; @@ -216,6 +217,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(None) => return, LocalRef::Operand(Some(operand)) => { + // Don't spill operands onto the stack in naked functions. + // See: https://github.com/rust-lang/rust/issues/42779 + let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + return; + } + // "Spill" the value onto the stack, for debuginfo, // without forcing non-debuginfo uses of the local // to also load from the stack every single time.