about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-07-16 00:23:17 +0200
committerEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-07-16 00:23:17 +0200
commitb5fde0dae0af1a4a273830e695dc0aaf7c3885ba (patch)
tree7c3e6dabf8e2eb1cc256a885eb2f767fa074cf98
parentad963232d9b987d66a6f8e6ec4141f672b8b9900 (diff)
downloadrust-b5fde0dae0af1a4a273830e695dc0aaf7c3885ba.tar.gz
rust-b5fde0dae0af1a4a273830e695dc0aaf7c3885ba.zip
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).
-rw-r--r--compiler/rustc_const_eval/messages.ftl3
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs19
-rw-r--r--src/tools/miri/tests/fail/function_calls/target_feature.rs11
-rw-r--r--src/tools/miri/tests/fail/function_calls/target_feature.stderr15
-rw-r--r--src/tools/miri/tests/pass/function_calls/target_feature.rs12
5 files changed, 60 insertions, 0 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index e99005316b3..d8eade5bd2a 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -399,6 +399,9 @@ const_eval_unallowed_mutable_refs_raw =
 const_eval_unallowed_op_in_const_context =
     {$msg}
 
+const_eval_unavailable_target_features_for_fn =
+    calling a function that requires unavailable target features: {$unavailable_feats}
+
 const_eval_undefined_behavior =
     it is undefined behavior to use this value
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index c944782b487..b6eea191aa6 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -503,6 +503,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     }
                 }
 
+                let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+                let missing_features: Vec<_> = attrs
+                    .target_features
+                    .iter()
+                    .copied()
+                    .filter(|feature| !self.tcx.sess.target_features.contains(feature))
+                    .collect();
+                if !missing_features.is_empty() {
+                    let mut missing_features_str = String::from(missing_features[0].as_str());
+                    for missing_feature in missing_features[1..].iter() {
+                        missing_features_str.push(',');
+                        missing_features_str.push_str(missing_feature.as_str());
+                    }
+                    throw_ub_custom!(
+                        fluent::const_eval_unavailable_target_features_for_fn,
+                        unavailable_feats = missing_features_str,
+                    );
+                }
+
                 if !callee_fn_abi.can_unwind {
                     // The callee cannot unwind, so force the `Unreachable` unwind handling.
                     unwind = mir::UnwindAction::Unreachable;
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs
new file mode 100644
index 00000000000..be95241ea67
--- /dev/null
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs
@@ -0,0 +1,11 @@
+//@only-target-x86_64: uses x86 target features
+
+fn main() {
+    assert!(!is_x86_feature_detected!("ssse3"));
+    unsafe {
+        ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
+    }
+}
+
+#[target_feature(enable = "ssse3")]
+unsafe fn ssse3_fn() {}
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
new file mode 100644
index 00000000000..bddc6e7e89b
--- /dev/null
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
+  --> $DIR/target_feature.rs:LL:CC
+   |
+LL |         ssse3_fn();
+   |         ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/target_feature.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/pass/function_calls/target_feature.rs b/src/tools/miri/tests/pass/function_calls/target_feature.rs
new file mode 100644
index 00000000000..0be86ba3731
--- /dev/null
+++ b/src/tools/miri/tests/pass/function_calls/target_feature.rs
@@ -0,0 +1,12 @@
+//@only-target-x86_64: uses x86 target features
+//@compile-flags: -C target-feature=+ssse3
+
+fn main() {
+    assert!(is_x86_feature_detected!("ssse3"));
+    unsafe {
+        ssse3_fn();
+    }
+}
+
+#[target_feature(enable = "ssse3")]
+unsafe fn ssse3_fn() {}