Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 912f7a6

Browse filesBrowse files
committed
Emit error when calling/declaring functions with unavailable vectors.
On some architectures, vector types may have a different ABI when relevant target features are enabled. As discussed in rust-lang/lang-team#235, this turns out to very easily lead to unsound code. This commit makes it an error to declare or call functions using those vector types in a context in which the corresponding target features are disabled, if using an ABI for which the difference is relevant.
1 parent 032be6f commit 912f7a6
Copy full SHA for 912f7a6

File tree

Expand file treeCollapse file tree

7 files changed

+196
-0
lines changed
Filter options
Expand file treeCollapse file tree

7 files changed

+196
-0
lines changed

‎Cargo.lock

Copy file name to clipboardExpand all lines: Cargo.lock
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,6 +4470,7 @@ dependencies = [
44704470
name = "rustc_monomorphize"
44714471
version = "0.0.0"
44724472
dependencies = [
4473+
"rustc_abi",
44734474
"rustc_data_structures",
44744475
"rustc_errors",
44754476
"rustc_fluent_macro",

‎compiler/rustc_monomorphize/Cargo.toml

Copy file name to clipboardExpand all lines: compiler/rustc_monomorphize/Cargo.toml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
rustc_abi = { path = "../rustc_abi" }
89
rustc_data_structures = { path = "../rustc_data_structures" }
910
rustc_errors = { path = "../rustc_errors" }
1011
rustc_fluent_macro = { path = "../rustc_fluent_macro" }

‎compiler/rustc_monomorphize/messages.ftl

Copy file name to clipboardExpand all lines: compiler/rustc_monomorphize/messages.ftl
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
monomorphize_abi_error_disabled_vector_type_call =
2+
ABI error: this function call uses a {$required_feature} vector type, which is not enabled in the caller
3+
.help = consider enabling it globally (-C target-feature=+{$required_feature}) or locally (#[target_feature(enable="{$required_feature}")])
4+
monomorphize_abi_error_disabled_vector_type_def =
5+
ABI error: this function definition uses a {$required_feature} vector type, which is not enabled
6+
.help = consider enabling it globally (-C target-feature=+{$required_feature}) or locally (#[target_feature(enable="{$required_feature}")])
7+
18
monomorphize_couldnt_dump_mono_stats =
29
unexpected error occurred while dumping monomorphization stats: {$error}
310

‎compiler/rustc_monomorphize/src/collector.rs

Copy file name to clipboardExpand all lines: compiler/rustc_monomorphize/src/collector.rs
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
//! this is not implemented however: a mono item will be produced
206206
//! regardless of whether it is actually needed or not.
207207
208+
mod abi_check;
208209
mod move_check;
209210

210211
use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock};
@@ -762,6 +763,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
762763
self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
763764
let callee_ty = self.monomorphize(callee_ty);
764765
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
766+
abi_check::check_call_site_abi(tcx, callee_ty, *fn_span, self.body.source.instance);
765767
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items)
766768
}
767769
mir::TerminatorKind::Drop { ref place, .. } => {
@@ -1199,6 +1201,7 @@ fn collect_items_of_instance<'tcx>(
11991201
mentioned_items: &mut MonoItems<'tcx>,
12001202
mode: CollectionMode,
12011203
) {
1204+
abi_check::check_instance_abi(tcx, instance);
12021205
let body = tcx.instance_mir(instance.def);
12031206
// Naively, in "used" collection mode, all functions get added to *both* `used_items` and
12041207
// `mentioned_items`. Mentioned items processing will then notice that they have already been
+111Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use rustc_abi::Abi;
2+
use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
3+
use rustc_span::{def_id::DefId, Span, Symbol};
4+
use rustc_target::abi::call::{FnAbi, PassMode};
5+
6+
use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef};
7+
8+
const SSE_FEATURES: &'static [&'static str] = &["sse", "sse2", "ssse3", "sse3", "sse4.1", "sse4.2"];
9+
const AVX_FEATURES: &'static [&'static str] = &["avx", "avx2", "f16c", "fma"];
10+
const AVX512_FEATURES: &'static [&'static str] = &[
11+
"avx512f",
12+
"avx512bw",
13+
"avx512cd",
14+
"avx512er",
15+
"avx512pf",
16+
"avx512vl",
17+
"avx512dq",
18+
"avx512ifma",
19+
"avx512vbmi",
20+
"avx512vnni",
21+
"avx512bitalg",
22+
"avx512vpopcntdq",
23+
"avx512bf16",
24+
"avx512vbmi2",
25+
];
26+
27+
fn do_check_abi<'tcx>(
28+
tcx: TyCtxt<'tcx>,
29+
abi: &FnAbi<'tcx, Ty<'tcx>>,
30+
target_feature_def: DefId,
31+
emit_err: impl Fn(&'static str),
32+
) {
33+
// FIXME: add support for other architectures
34+
if tcx.sess.target.arch != "x86" && tcx.sess.target.arch != "x86_64" {
35+
return;
36+
}
37+
let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
38+
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
39+
let size = arg_abi.layout.size;
40+
if matches!(arg_abi.layout.abi, Abi::Vector { .. })
41+
&& matches!(arg_abi.mode, PassMode::Direct(_))
42+
{
43+
let features: &[_] = match size.bits() {
44+
x if x <= 128 => &[SSE_FEATURES, AVX_FEATURES, AVX512_FEATURES],
45+
x if x <= 256 => &[AVX_FEATURES, AVX512_FEATURES],
46+
x if x <= 512 => &[AVX512_FEATURES],
47+
_ => {
48+
panic!("Unknown vector size for x86: {}; arg = {:?}", size.bits(), arg_abi)
49+
}
50+
};
51+
let required_feature = features.iter().map(|x| x.iter()).flatten().next().unwrap();
52+
if !features.iter().map(|x| x.iter()).flatten().any(|feature| {
53+
let required_feature_sym = Symbol::intern(feature);
54+
tcx.sess.unstable_target_features.contains(&required_feature_sym)
55+
|| codegen_attrs.target_features.contains(&required_feature_sym)
56+
}) {
57+
emit_err(required_feature);
58+
}
59+
}
60+
}
61+
}
62+
63+
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
64+
/// or return values for which the corresponding target feature is not enabled.
65+
pub fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
66+
let param_env = ParamEnv::reveal_all();
67+
let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else {
68+
// An error will be reported during codegen if we cannot determine the ABI of this
69+
// function.
70+
return;
71+
};
72+
do_check_abi(tcx, abi, instance.def_id(), |required_feature| {
73+
tcx.dcx().emit_err(AbiErrorDisabledVectorTypeDef {
74+
span: tcx.def_span(instance.def_id()),
75+
required_feature,
76+
});
77+
})
78+
}
79+
80+
/// Checks that a call expression does not try to pass a vector-passed argument which requires a
81+
/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch.
82+
pub fn check_call_site_abi<'tcx>(
83+
tcx: TyCtxt<'tcx>,
84+
ty: Ty<'tcx>,
85+
span: Span,
86+
caller: InstanceKind<'tcx>,
87+
) {
88+
let param_env = ParamEnv::reveal_all();
89+
let callee_abi = match *ty.kind() {
90+
ty::FnPtr(sig) => tcx.fn_abi_of_fn_ptr(param_env.and((sig, ty::List::empty()))),
91+
ty::FnDef(def_id, args) => {
92+
// Intrinsics are handled separately by the compiler.
93+
if tcx.intrinsic(def_id).is_some() {
94+
return;
95+
}
96+
let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, span);
97+
tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty())))
98+
}
99+
_ => {
100+
panic!("Invalid function call");
101+
}
102+
};
103+
104+
let Ok(callee_abi) = callee_abi else {
105+
// ABI failed to compute; this will not get through codegen.
106+
return;
107+
};
108+
do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| {
109+
tcx.dcx().emit_err(AbiErrorDisabledVectorTypeCall { span, required_feature });
110+
})
111+
}

‎compiler/rustc_monomorphize/src/errors.rs

Copy file name to clipboardExpand all lines: compiler/rustc_monomorphize/src/errors.rs
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,21 @@ pub struct StartNotFound;
9191
pub struct UnknownCguCollectionMode<'a> {
9292
pub mode: &'a str,
9393
}
94+
95+
#[derive(Diagnostic)]
96+
#[diag(monomorphize_abi_error_disabled_vector_type_def)]
97+
#[help]
98+
pub struct AbiErrorDisabledVectorTypeDef<'a> {
99+
#[primary_span]
100+
pub span: Span,
101+
pub required_feature: &'a str,
102+
}
103+
104+
#[derive(Diagnostic)]
105+
#[diag(monomorphize_abi_error_disabled_vector_type_call)]
106+
#[help]
107+
pub struct AbiErrorDisabledVectorTypeCall<'a> {
108+
#[primary_span]
109+
pub span: Span,
110+
pub required_feature: &'a str,
111+
}

‎tests/ui/simd-abi-checks.rs

Copy file name to clipboard
+55Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@ only-x86_64
2+
//@ build-fail
3+
4+
#![feature(avx512_target_feature)]
5+
#![feature(portable_simd)]
6+
#![allow(improper_ctypes_definitions)]
7+
8+
use std::arch::x86_64::*;
9+
10+
unsafe extern "C" fn f(_: __m256) {
11+
//~^ ABI error: this function definition uses a avx vector type, which is not enabled
12+
todo!()
13+
}
14+
15+
unsafe extern "C" fn g() -> __m256 {
16+
//~^ ABI error: this function definition uses a avx vector type, which is not enabled
17+
todo!()
18+
}
19+
20+
#[target_feature(enable = "avx")]
21+
unsafe extern "C" fn favx(_: __m256) {
22+
todo!()
23+
}
24+
25+
#[target_feature(enable = "avx")]
26+
unsafe extern "C" fn gavx() -> __m256 {
27+
todo!()
28+
}
29+
30+
fn as_f64x8(d: __m512d) -> std::simd::f64x8 {
31+
unsafe { std::mem::transmute(d) }
32+
}
33+
34+
unsafe fn test() {
35+
let arg = std::mem::transmute([0.0f64; 8]);
36+
as_f64x8(arg);
37+
}
38+
39+
fn main() {
40+
unsafe {
41+
f(g());
42+
//~^ ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller
43+
//~| ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller
44+
}
45+
46+
unsafe {
47+
favx(gavx());
48+
//~^ ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller
49+
//~| ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller
50+
}
51+
52+
unsafe {
53+
test();
54+
}
55+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.