Skip to content

Commit 94f8a30

Browse files
committed
ctutils: use new cmov trait impls; remove unsafe
In #1404 impls of `Cmov` and `CmovEq` were added to the `NonZero*` and `Ordering` types and slices thereof, which is what the unsafe code in `ctutils` existed to handle. Now they can be handled like the other types `cmov` already has trait impls for. And with that, we can remove all of the unsafe code in this crate, with all of it having been factored into the `cmov` crate, which makes that the one place to look for `unsafe` auditing. With all the `unsafe` removed, this also adds `forbid(unsafe_code)`.
1 parent 5262484 commit 94f8a30

File tree

6 files changed

+72
-108
lines changed

6 files changed

+72
-108
lines changed

Cargo.lock

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ctutils/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ edition = "2024"
1717
rust-version = "1.85"
1818

1919
[dependencies]
20-
cmov = "0.5"
20+
cmov = "0.5.1"
2121

2222
# optional dependencies
2323
subtle = { version = "2", optional = true, default-features = false }

ctutils/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
55
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
66
)]
7-
#![deny(unsafe_code)]
7+
#![forbid(unsafe_code)] // `unsafe` should go in `cmov`
88
#![warn(
99
clippy::borrow_as_ptr,
1010
clippy::cast_lossless,

ctutils/src/traits/ct_assign.rs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Choice, CtSelect};
1+
use crate::Choice;
22
use cmov::Cmov;
33
use core::{
44
cmp,
@@ -8,6 +8,9 @@ use core::{
88
},
99
};
1010

11+
#[cfg(feature = "subtle")]
12+
use crate::CtSelect;
13+
1114
#[cfg(doc)]
1215
use core::num::NonZero;
1316

@@ -86,29 +89,18 @@ macro_rules! impl_ct_assign_slice_with_cmov {
8689
};
8790
}
8891

89-
impl_ct_assign_slice_with_cmov!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
90-
impl_ct_assign_with_cmov!(isize, usize);
91-
impl CtAssignSlice for isize {}
92-
impl CtAssignSlice for usize {}
93-
94-
/// Impl `CtAssign` using the `CtSelect` trait.
95-
macro_rules! impl_ct_assign_with_ct_select {
96-
( $($ty:ty),+ ) => {
97-
$(
98-
impl CtAssign for $ty {
99-
#[inline]
100-
fn ct_assign(&mut self, rhs: &Self, choice: Choice) {
101-
*self = Self::ct_select(self, rhs, choice);
102-
}
103-
}
104-
105-
impl CtAssignSlice for $ty {}
106-
)+
107-
};
108-
}
109-
110-
impl_ct_assign_with_ct_select!(
111-
cmp::Ordering,
92+
// NOTE: impls `CtAssign` and `CtAssignSlice`
93+
impl_ct_assign_slice_with_cmov!(
94+
i8,
95+
i16,
96+
i32,
97+
i64,
98+
i128,
99+
u8,
100+
u16,
101+
u32,
102+
u64,
103+
u128,
112104
NonZeroI8,
113105
NonZeroI16,
114106
NonZeroI32,
@@ -118,9 +110,14 @@ impl_ct_assign_with_ct_select!(
118110
NonZeroU16,
119111
NonZeroU32,
120112
NonZeroU64,
121-
NonZeroU128
113+
NonZeroU128,
114+
cmp::Ordering
122115
);
123116

117+
impl_ct_assign_with_cmov!(isize, usize);
118+
impl CtAssignSlice for isize {}
119+
impl CtAssignSlice for usize {}
120+
124121
impl<T, const N: usize> CtAssign for [T; N]
125122
where
126123
T: CtAssignSlice,

ctutils/src/traits/ct_neg.rs

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@ macro_rules! impl_signed_ct_neg {
2525
impl CtNeg for $int {
2626
#[inline]
2727
fn ct_neg(&self, choice: Choice) -> Self {
28-
let neg = -*self;
29-
self.ct_select(&neg, choice)
28+
self.ct_select(&-*self, choice)
3029
}
3130

3231
#[inline]
3332
fn ct_neg_assign(&mut self, choice: Choice) {
34-
let neg = -*self;
35-
self.ct_assign(&neg, choice)
33+
self.ct_assign(&-*self, choice)
3634
}
3735
}
3836
)+
@@ -46,58 +44,52 @@ macro_rules! impl_unsigned_ct_neg {
4644
impl CtNeg for $uint {
4745
#[inline]
4846
fn ct_neg(&self, choice: Choice) -> Self {
49-
let neg = self.wrapping_neg();
50-
self.ct_select(&neg, choice)
47+
self.ct_select(&self.wrapping_neg(), choice)
5148
}
5249

5350
#[inline]
5451
fn ct_neg_assign(&mut self, choice: Choice) {
55-
let neg = self.wrapping_neg();
56-
self.ct_assign(&neg, choice)
52+
self.ct_assign(&self.wrapping_neg(), choice)
5753
}
5854
}
5955
)+
6056
};
6157
}
6258

63-
impl_signed_ct_neg!(i8, i16, i32, i64, i128);
59+
impl_signed_ct_neg!(
60+
i8,
61+
i16,
62+
i32,
63+
i64,
64+
i128,
65+
NonZeroI8,
66+
NonZeroI16,
67+
NonZeroI32,
68+
NonZeroI64,
69+
NonZeroI128
70+
);
6471
impl_unsigned_ct_neg!(u8, u16, u32, u64, u128);
6572

66-
/// Impl `CtNeg` for `NonZero<T>` by calling the `CtNeg` impl for `T`.
67-
macro_rules! impl_ct_neg_for_nonzero_integer {
68-
( $($nzint:ident),+ ) => {
73+
/// Unfortunately `NonZeroU*` doesn't support `wrapping_neg` for some reason (but `NonZeroI*` does),
74+
/// even though the wrapping negation of any non-zero integer should also be non-zero.
75+
///
76+
/// So we need a special case just for `NonZeroU*`, at least for now.
77+
macro_rules! impl_ct_neg_for_unsigned_nonzero {
78+
( $($nzuint:ident),+ ) => {
6979
$(
70-
impl CtNeg for $nzint {
80+
impl CtNeg for $nzuint {
7181
#[inline]
7282
fn ct_neg(&self, choice: Choice) -> Self {
73-
let n = self.get().ct_neg(choice);
74-
75-
// SAFETY: we are constructing `NonZero` from a value we obtained from
76-
// `NonZero::get`, which ensures it's non-zero, and the negation of a non-zero
77-
// integer will always be non-zero:
78-
//
79-
// - signed: `{i*}::MIN` and `{i*}::MAX` are each other's negations
80-
// - unsigned: `1` and `{u*}::MAX` are each other's negations
81-
#[allow(unsafe_code)]
82-
unsafe { $nzint::new_unchecked(n) }
83+
// TODO(tarcieri): use `NonZero::wrapping_neg` if it becomes available
84+
let n = self.get().ct_select(&self.get().wrapping_neg(), choice);
85+
$nzuint::new(n).expect("should be non-zero")
8386
}
8487
}
8588
)+
8689
};
8790
}
8891

89-
impl_ct_neg_for_nonzero_integer!(
90-
NonZeroI8,
91-
NonZeroI16,
92-
NonZeroI32,
93-
NonZeroI64,
94-
NonZeroI128,
95-
NonZeroU8,
96-
NonZeroU16,
97-
NonZeroU32,
98-
NonZeroU64,
99-
NonZeroU128
100-
);
92+
impl_ct_neg_for_unsigned_nonzero!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128);
10193

10294
#[cfg(test)]
10395
mod tests {

ctutils/src/traits/ct_select.rs

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -92,29 +92,18 @@ macro_rules! impl_ct_select_with_ct_assign {
9292
}
9393

9494
impl_ct_select_with_ct_assign!(
95-
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
96-
);
97-
98-
/// Impl `CtSelect` for `NonZero<T>` by calling the `CtSelect` impl for `T`.
99-
macro_rules! impl_ct_select_for_nonzero_integer {
100-
( $($nzint:ident),+ ) => {
101-
$(
102-
impl CtSelect for $nzint {
103-
#[inline]
104-
fn ct_select(&self, rhs: &Self, choice: Choice) -> Self {
105-
let n = self.get().ct_select(&rhs.get(), choice);
106-
107-
// SAFETY: we are constructing `NonZero` from a value we obtained from
108-
// `NonZero::get`, which ensures it's non-zero.
109-
#[allow(unsafe_code)]
110-
unsafe { $nzint::new_unchecked(n) }
111-
}
112-
}
113-
)+
114-
};
115-
}
116-
117-
impl_ct_select_for_nonzero_integer!(
95+
i8,
96+
i16,
97+
i32,
98+
i64,
99+
i128,
100+
isize,
101+
u8,
102+
u16,
103+
u32,
104+
u64,
105+
u128,
106+
usize,
118107
NonZeroI8,
119108
NonZeroI16,
120109
NonZeroI32,
@@ -124,30 +113,10 @@ impl_ct_select_for_nonzero_integer!(
124113
NonZeroU16,
125114
NonZeroU32,
126115
NonZeroU64,
127-
NonZeroU128
116+
NonZeroU128,
117+
cmp::Ordering
128118
);
129119

130-
impl CtSelect for cmp::Ordering {
131-
fn ct_select(&self, other: &Self, choice: Choice) -> Self {
132-
// `Ordering` is `#[repr(i8)]` where:
133-
//
134-
// - `Less` => -1
135-
// - `Equal` => 0
136-
// - `Greater` => 1
137-
//
138-
// Given this, it's possible to operate on orderings as if they're `i8`, which allows us to
139-
// use the `CtSelect` impl on `i8` to select between them.
140-
let ret = (*self as i8).ct_select(&(*other as i8), choice);
141-
142-
// SAFETY: `Ordering` is `#[repr(i8)]` and `ret` has been assigned to
143-
// a value which was originally a valid `Ordering` then cast to `i8`
144-
#[allow(trivial_casts, unsafe_code)]
145-
unsafe {
146-
*(&raw const ret).cast::<Self>()
147-
}
148-
}
149-
}
150-
151120
#[cfg(feature = "subtle")]
152121
impl CtSelect for subtle::Choice {
153122
#[inline]

0 commit comments

Comments
 (0)