about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2025-04-17 17:29:32 +0200
committerAmanieu d'Antras <amanieu@gmail.com>2025-04-17 17:30:53 +0200
commite5e5fb9d805dacdd5ceaf73254d61726d75f455a (patch)
tree52f4948b133762ce2105337c11273b73cc4ba4cc /library/core
parent94015d3cd4b48d098abd0f3e44af97dab2b713b4 (diff)
downloadrust-e5e5fb9d805dacdd5ceaf73254d61726d75f455a.tar.gz
rust-e5e5fb9d805dacdd5ceaf73254d61726d75f455a.zip
Fix drop handling in `hint::select_unpredictable`
This intrinsic doesn't drop the value that is not selected so this is
manually done in the public function that wraps the intrinsic.
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/hint.rs30
-rw-r--r--library/core/src/intrinsics/mod.rs2
2 files changed, 23 insertions, 9 deletions
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index f6708cc4bc9..1ca23ab6eea 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -4,6 +4,7 @@
 //!
 //! Hints may be compile time or runtime.
 
+use crate::mem::MaybeUninit;
 use crate::{intrinsics, ub_checks};
 
 /// Informs the compiler that the site which is calling this function is not
@@ -735,9 +736,9 @@ pub const fn cold_path() {
     crate::intrinsics::cold_path()
 }
 
-/// Returns either `true_val` or `false_val` depending on the value of `b`,
-/// with a hint to the compiler that `b` is unlikely to be correctly
-/// predicted by a CPU’s branch predictor.
+/// Returns either `true_val` or `false_val` depending on the value of
+/// `condition`, with a hint to the compiler that `condition` is unlikely to be
+/// correctly predicted by a CPU’s branch predictor.
 ///
 /// This method is functionally equivalent to
 /// ```ignore (this is just for illustrative purposes)
@@ -753,10 +754,10 @@ pub const fn cold_path() {
 /// search.
 ///
 /// Note however that this lowering is not guaranteed (on any platform) and
-/// should not be relied upon when trying to write constant-time code. Also
-/// be aware that this lowering might *decrease* performance if `condition`
-/// is well-predictable. It is advisable to perform benchmarks to tell if
-/// this function is useful.
+/// should not be relied upon when trying to write cryptographic constant-time
+/// code. Also be aware that this lowering might *decrease* performance if
+/// `condition` is well-predictable. It is advisable to perform benchmarks to
+/// tell if this function is useful.
 ///
 /// # Examples
 ///
@@ -780,6 +781,17 @@ pub const fn cold_path() {
 /// ```
 #[inline(always)]
 #[unstable(feature = "select_unpredictable", issue = "133962")]
-pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
-    crate::intrinsics::select_unpredictable(b, true_val, false_val)
+pub fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T {
+    // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245):
+    // Change this to use ManuallyDrop instead.
+    let mut true_val = MaybeUninit::new(true_val);
+    let mut false_val = MaybeUninit::new(false_val);
+    // SAFETY: The value that is not selected is dropped, and the selected one
+    // is returned. This is necessary because the intrinsic doesn't drop the
+    // value that is  not selected.
+    unsafe {
+        crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val)
+            .assume_init_drop();
+        crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init()
+    }
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index e5604d277f5..a01efb2adeb 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1327,6 +1327,8 @@ pub const fn unlikely(b: bool) -> bool {
 /// any safety invariants.
 ///
 /// The public form of this instrinsic is [`core::hint::select_unpredictable`].
+/// However unlike the public form, the intrinsic will not drop the value that
+/// is not selected.
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
 #[rustc_nounwind]