From 3d7476eae1f4903684426835e97ba8f5d337c300 Mon Sep 17 00:00:00 2001 From: Levente Kurusa Date: Mon, 1 Oct 2018 15:13:42 +0200 Subject: [PATCH] codegen_llvm: verify that inline assembly operands are scalars Otherwise, LLVM translation will fail with a panic. Signed-off-by: Levente Kurusa --- src/librustc_codegen_llvm/diagnostics.rs | 11 +++++ src/librustc_codegen_llvm/mir/statement.rs | 28 ++++++++--- src/test/ui/inline-asm-bad-operand.rs | 57 ++++++++++++++++++++++ src/test/ui/inline-asm-bad-operand.stderr | 33 +++++++++++++ 4 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/inline-asm-bad-operand.rs create mode 100644 src/test/ui/inline-asm-bad-operand.stderr diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs index 242b7a1a119f7..5721938c9c0a7 100644 --- a/src/librustc_codegen_llvm/diagnostics.rs +++ b/src/librustc_codegen_llvm/diagnostics.rs @@ -69,4 +69,15 @@ fn main() { ``` "##, +E0669: r##" +Cannot convert inline assembly operand to a single LLVM value. + +This error usually happens when trying to pass in a value to an input inline +assembly operand that is actually a pair of values. In particular, this can +happen when trying to pass in a slice, for instance a `&str`. In Rust, these +values are represented internally as a pair of values, the pointer and its +length. When passed as an input operand, this pair of values can not be +coerced into a register and thus we must fail with an error. +"##, + } diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs index 6bd41bfe16fee..93be0074f6e9b 100644 --- a/src/librustc_codegen_llvm/mir/statement.rs +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -15,6 +15,7 @@ use builder::Builder; use super::FunctionCx; use super::LocalRef; +use super::OperandValue; impl FunctionCx<'a, 'll, 'tcx> { pub fn codegen_statement(&mut self, @@ -82,14 +83,27 @@ impl FunctionCx<'a, 'll, 'tcx> { self.codegen_place(&bx, output) }).collect(); - let input_vals = inputs.iter().map(|input| { - self.codegen_operand(&bx, input).immediate() - }).collect(); + let input_vals = inputs.iter() + .try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| { + let op = self.codegen_operand(&bx, input); + if let OperandValue::Immediate(_) = op.val { + acc.push(op.immediate()); + Ok(acc) + } else { + Err(op) + } + }); - let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals); - if !res { - span_err!(bx.sess(), statement.source_info.span, E0668, - "malformed inline assembly"); + if input_vals.is_err() { + span_err!(bx.sess(), statement.source_info.span, E0669, + "invalid value for constraint in inline assembly"); + } else { + let input_vals = input_vals.unwrap(); + let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals); + if !res { + span_err!(bx.sess(), statement.source_info.span, E0668, + "malformed inline assembly"); + } } bx } diff --git a/src/test/ui/inline-asm-bad-operand.rs b/src/test/ui/inline-asm-bad-operand.rs new file mode 100644 index 0000000000000..37021f38cacdf --- /dev/null +++ b/src/test/ui/inline-asm-bad-operand.rs @@ -0,0 +1,57 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the compiler will catch passing invalid values to inline assembly +// operands. + +#![feature(asm)] + +#[repr(C)] +struct MyPtr(usize); + +fn main() { + issue_37433(); + issue_37437(); + issue_40187(); + issue_54067(); +} + +fn issue_37433() { + unsafe { + asm!("" :: "r"("")); //~ ERROR E0669 + } + + unsafe { + let target = MyPtr(0); + asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669 + } +} + +fn issue_37437() { + let hello: &str = "hello"; + // this should fail... + unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669 + // but this should succeed. + unsafe { asm!("" :: "r"(hello.as_ptr())) }; +} + +fn issue_40187() { + let arr: [u8; 1] = [0; 1]; + unsafe { + asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669 + } +} + +fn issue_54067() { + let addr: Option = Some(123); + unsafe { + asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669 + } +} diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr new file mode 100644 index 0000000000000..6971215a95f9e --- /dev/null +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -0,0 +1,33 @@ +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/inline-asm-bad-operand.rs:28:9 + | +LL | asm!("" :: "r"("")); //~ ERROR E0669 + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/inline-asm-bad-operand.rs:33:9 + | +LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/inline-asm-bad-operand.rs:40:14 + | +LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669 + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/inline-asm-bad-operand.rs:48:9 + | +LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/inline-asm-bad-operand.rs:55:9 + | +LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0669`.