Skip to content

Commit 3d7476e

Browse files
committed
codegen_llvm: verify that inline assembly operands are scalars
Otherwise, LLVM translation will fail with a panic. Signed-off-by: Levente Kurusa <[email protected]>
1 parent 6188c58 commit 3d7476e

File tree

4 files changed

+122
-7
lines changed

4 files changed

+122
-7
lines changed

src/librustc_codegen_llvm/diagnostics.rs

+11
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,15 @@ fn main() {
6969
```
7070
"##,
7171

72+
E0669: r##"
73+
Cannot convert inline assembly operand to a single LLVM value.
74+
75+
This error usually happens when trying to pass in a value to an input inline
76+
assembly operand that is actually a pair of values. In particular, this can
77+
happen when trying to pass in a slice, for instance a `&str`. In Rust, these
78+
values are represented internally as a pair of values, the pointer and its
79+
length. When passed as an input operand, this pair of values can not be
80+
coerced into a register and thus we must fail with an error.
81+
"##,
82+
7283
}

src/librustc_codegen_llvm/mir/statement.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use builder::Builder;
1515

1616
use super::FunctionCx;
1717
use super::LocalRef;
18+
use super::OperandValue;
1819

1920
impl FunctionCx<'a, 'll, 'tcx> {
2021
pub fn codegen_statement(&mut self,
@@ -82,14 +83,27 @@ impl FunctionCx<'a, 'll, 'tcx> {
8283
self.codegen_place(&bx, output)
8384
}).collect();
8485

85-
let input_vals = inputs.iter().map(|input| {
86-
self.codegen_operand(&bx, input).immediate()
87-
}).collect();
86+
let input_vals = inputs.iter()
87+
.try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
88+
let op = self.codegen_operand(&bx, input);
89+
if let OperandValue::Immediate(_) = op.val {
90+
acc.push(op.immediate());
91+
Ok(acc)
92+
} else {
93+
Err(op)
94+
}
95+
});
8896

89-
let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
90-
if !res {
91-
span_err!(bx.sess(), statement.source_info.span, E0668,
92-
"malformed inline assembly");
97+
if input_vals.is_err() {
98+
span_err!(bx.sess(), statement.source_info.span, E0669,
99+
"invalid value for constraint in inline assembly");
100+
} else {
101+
let input_vals = input_vals.unwrap();
102+
let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
103+
if !res {
104+
span_err!(bx.sess(), statement.source_info.span, E0668,
105+
"malformed inline assembly");
106+
}
93107
}
94108
bx
95109
}

src/test/ui/inline-asm-bad-operand.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the compiler will catch passing invalid values to inline assembly
12+
// operands.
13+
14+
#![feature(asm)]
15+
16+
#[repr(C)]
17+
struct MyPtr(usize);
18+
19+
fn main() {
20+
issue_37433();
21+
issue_37437();
22+
issue_40187();
23+
issue_54067();
24+
}
25+
26+
fn issue_37433() {
27+
unsafe {
28+
asm!("" :: "r"("")); //~ ERROR E0669
29+
}
30+
31+
unsafe {
32+
let target = MyPtr(0);
33+
asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
34+
}
35+
}
36+
37+
fn issue_37437() {
38+
let hello: &str = "hello";
39+
// this should fail...
40+
unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
41+
// but this should succeed.
42+
unsafe { asm!("" :: "r"(hello.as_ptr())) };
43+
}
44+
45+
fn issue_40187() {
46+
let arr: [u8; 1] = [0; 1];
47+
unsafe {
48+
asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
49+
}
50+
}
51+
52+
fn issue_54067() {
53+
let addr: Option<u32> = Some(123);
54+
unsafe {
55+
asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
56+
}
57+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0669]: invalid value for constraint in inline assembly
2+
--> $DIR/inline-asm-bad-operand.rs:28:9
3+
|
4+
LL | asm!("" :: "r"("")); //~ ERROR E0669
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0669]: invalid value for constraint in inline assembly
8+
--> $DIR/inline-asm-bad-operand.rs:33:9
9+
|
10+
LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0669]: invalid value for constraint in inline assembly
14+
--> $DIR/inline-asm-bad-operand.rs:40:14
15+
|
16+
LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error[E0669]: invalid value for constraint in inline assembly
20+
--> $DIR/inline-asm-bad-operand.rs:48:9
21+
|
22+
LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error[E0669]: invalid value for constraint in inline assembly
26+
--> $DIR/inline-asm-bad-operand.rs:55:9
27+
|
28+
LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: aborting due to 5 previous errors
32+
33+
For more information about this error, try `rustc --explain E0669`.

0 commit comments

Comments
 (0)