Skip to content

Commit

Permalink
codegen_llvm: verify that inline assembly operands are scalars
Browse files Browse the repository at this point in the history
Otherwise, LLVM translation will fail with a panic.

Signed-off-by: Levente Kurusa <lkurusa@acm.org>
  • Loading branch information
levex committed Oct 6, 2018
1 parent 6188c58 commit 3d7476e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/librustc_codegen_llvm/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"##,

}
28 changes: 21 additions & 7 deletions src/librustc_codegen_llvm/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down
57 changes: 57 additions & 0 deletions src/test/ui/inline-asm-bad-operand.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<u32> = Some(123);
unsafe {
asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
}
}
33 changes: 33 additions & 0 deletions src/test/ui/inline-asm-bad-operand.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 3d7476e

Please sign in to comment.