Skip to content

Commit 1787f31

Browse files
committed
Auto merge of #113720 - eduardosm:miri-target-feature, r=RalfJung,oli-obk
miri: fail when calling a function that requires an unavailable target feature miri will report an UB when calling a function that has a `#[target_feature(enable = ...)]` attribute is called and the required feature is not available. "Available features" are the same that `is_x86_feature_detected!` (or equivalent) reports to be available during miri execution (which can be enabled or disabled with the `-C target-feature` flag).
2 parents 4eaad89 + ae2a72d commit 1787f31

File tree

7 files changed

+97
-0
lines changed

7 files changed

+97
-0
lines changed

compiler/rustc_const_eval/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ const_eval_unallowed_mutable_refs_raw =
399399
const_eval_unallowed_op_in_const_context =
400400
{$msg}
401401
402+
const_eval_unavailable_target_features_for_fn =
403+
calling a function that requires unavailable target features: {$unavailable_feats}
404+
402405
const_eval_undefined_behavior =
403406
it is undefined behavior to use this value
404407

compiler/rustc_const_eval/src/interpret/terminator.rs

+30
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
503503
}
504504
}
505505

506+
// Check that all target features required by the callee (i.e., from
507+
// the attribute `#[target_feature(enable = ...)]`) are enabled at
508+
// compile time.
509+
self.check_fn_target_features(instance)?;
510+
506511
if !callee_fn_abi.can_unwind {
507512
// The callee cannot unwind, so force the `Unreachable` unwind handling.
508513
unwind = mir::UnwindAction::Unreachable;
@@ -786,6 +791,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
786791
}
787792
}
788793

794+
fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
795+
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
796+
if attrs
797+
.target_features
798+
.iter()
799+
.any(|feature| !self.tcx.sess.target_features.contains(feature))
800+
{
801+
throw_ub_custom!(
802+
fluent::const_eval_unavailable_target_features_for_fn,
803+
unavailable_feats = attrs
804+
.target_features
805+
.iter()
806+
.filter(|&feature| !self.tcx.sess.target_features.contains(feature))
807+
.fold(String::new(), |mut s, feature| {
808+
if !s.is_empty() {
809+
s.push_str(", ");
810+
}
811+
s.push_str(feature.as_str());
812+
s
813+
}),
814+
);
815+
}
816+
Ok(())
817+
}
818+
789819
fn drop_in_place(
790820
&mut self,
791821
place: &PlaceTy<'tcx, M::Provenance>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@only-target-x86_64: uses x86 target features
2+
3+
fn main() {
4+
assert!(!is_x86_feature_detected!("ssse3"));
5+
unsafe {
6+
ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
7+
}
8+
}
9+
10+
#[target_feature(enable = "ssse3")]
11+
unsafe fn ssse3_fn() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
2+
--> $DIR/target_feature.rs:LL:CC
3+
|
4+
LL | ssse3_fn();
5+
| ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/target_feature.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@only-target-x86_64: uses x86 target features
2+
//@compile-flags: -C target-feature=+ssse3
3+
4+
fn main() {
5+
assert!(is_x86_feature_detected!("ssse3"));
6+
unsafe {
7+
ssse3_fn();
8+
}
9+
}
10+
11+
#[target_feature(enable = "ssse3")]
12+
unsafe fn ssse3_fn() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// only-x86_64
2+
// compile-flags:-C target-feature=+ssse3
3+
4+
#![crate_type = "lib"]
5+
6+
// ok (ssse3 enabled at compile time)
7+
const A: () = unsafe { ssse3_fn() };
8+
9+
// error (avx2 not enabled at compile time)
10+
const B: () = unsafe { avx2_fn() };
11+
//~^ ERROR evaluation of constant value failed
12+
13+
#[target_feature(enable = "ssse3")]
14+
const unsafe fn ssse3_fn() {}
15+
16+
#[target_feature(enable = "avx2")]
17+
const unsafe fn avx2_fn() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/const_fn_target_feature.rs:10:24
3+
|
4+
LL | const B: () = unsafe { avx2_fn() };
5+
| ^^^^^^^^^ calling a function that requires unavailable target features: avx2
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)