Skip to content

Commit 09145a6

Browse files
authored
Replace as casts with safer conversions (#510)
1 parent 74e2391 commit 09145a6

12 files changed

+72
-48
lines changed

.clippy.toml

-1
This file was deleted.

.github/workflows/workspace.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
# Fixed Nigthly version is used to prevent
2424
# CI failures which are not relevant to PR changes
2525
# on introduction of new Clippy lints.
26-
toolchain: nightly-2024-09-04
26+
toolchain: nightly-2024-10-08
2727
components: clippy,rust-src
2828
- name: std feature
2929
run: cargo clippy --features std

src/error.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,14 @@ impl Error {
8888
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
8989
#[inline]
9090
pub fn raw_os_error(self) -> Option<i32> {
91-
if self.0.get() < Self::INTERNAL_START {
92-
match () {
93-
#[cfg(target_os = "solid_asp3")]
94-
// On SOLID, negate the error code again to obtain the original
95-
// error code.
96-
() => Some(-(self.0.get() as i32)),
97-
#[cfg(not(target_os = "solid_asp3"))]
98-
() => Some(self.0.get() as i32),
91+
i32::try_from(self.0.get()).ok().map(|errno| {
92+
// On SOLID, negate the error code again to obtain the original error code.
93+
if cfg!(target_os = "solid_asp3") {
94+
-errno
95+
} else {
96+
errno
9997
}
100-
} else {
101-
None
102-
}
98+
})
10399
}
104100

105101
/// Creates a new instance of an `Error` from a particular custom error code.

src/hermit.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@ extern "C" {
99
pub fn getrandom_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
1010
while !dest.is_empty() {
1111
let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::<u8>(), dest.len(), 0) };
12-
// Positive `isize`s can be safely casted to `usize`
13-
if res > 0 && (res as usize) <= dest.len() {
14-
dest = &mut dest[res as usize..];
15-
} else {
16-
let err = if res < 0 {
17-
u32::try_from(res.unsigned_abs())
12+
match res {
13+
res if res > 0 => {
14+
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
15+
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
16+
}
17+
code => {
18+
let err = u32::try_from(code.unsigned_abs())
1819
.ok()
19-
.map_or(Error::UNEXPECTED, Error::from_os_error)
20-
} else {
21-
Error::UNEXPECTED
22-
};
23-
return Err(err);
20+
.map_or(Error::UNEXPECTED, Error::from_os_error);
21+
return Err(err);
22+
}
2423
}
2524
}
2625
Ok(())

src/js.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
99

1010
// Size of our temporary Uint8Array buffer used with WebCrypto methods
1111
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
12-
const WEB_CRYPTO_BUFFER_SIZE: usize = 256;
12+
const WEB_CRYPTO_BUFFER_SIZE: u16 = 256;
1313
// Node.js's crypto.randomFillSync requires the size to be less than 2**31.
1414
const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1;
1515

@@ -50,10 +50,14 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error>
5050
RngSource::Web(crypto, buf) => {
5151
// getRandomValues does not work with all types of WASM memory,
5252
// so we initially write to browser memory to avoid exceptions.
53-
for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE) {
53+
for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE.into()) {
54+
let chunk_len: u32 = chunk
55+
.len()
56+
.try_into()
57+
.expect("chunk length is bounded by WEB_CRYPTO_BUFFER_SIZE");
5458
// The chunk can be smaller than buf's length, so we call to
5559
// JS to create a smaller view of buf without allocation.
56-
let sub_buf = buf.subarray(0, chunk.len() as u32);
60+
let sub_buf = buf.subarray(0, chunk_len);
5761

5862
if crypto.get_random_values(&sub_buf).is_err() {
5963
return Err(Error::WEB_GET_RANDOM_VALUES);
@@ -95,7 +99,7 @@ fn getrandom_init() -> Result<RngSource, Error> {
9599
},
96100
};
97101

98-
let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE as u32);
102+
let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into());
99103
Ok(RngSource::Web(crypto, buf))
100104
}
101105

src/lib.rs

+15
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,21 @@
241241
#![no_std]
242242
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
243243
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
244+
#![deny(
245+
clippy::cast_lossless,
246+
clippy::cast_possible_truncation,
247+
clippy::cast_possible_wrap,
248+
clippy::cast_precision_loss,
249+
clippy::cast_ptr_alignment,
250+
clippy::cast_sign_loss,
251+
clippy::char_lit_as_u8,
252+
clippy::checked_conversions,
253+
clippy::fn_to_numeric_cast,
254+
clippy::fn_to_numeric_cast_with_truncation,
255+
clippy::ptr_as_ptr,
256+
clippy::unnecessary_cast,
257+
clippy::useless_conversion
258+
)]
244259

245260
#[macro_use]
246261
extern crate cfg_if;

src/linux_android.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
66
util_libc::sys_fill_exact(dest, getrandom_syscall)
77
}
88

9-
// Also used by linux_android_with_fallback to check if the syscall is available.
109
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
11-
unsafe {
10+
let res: libc::c_long = unsafe {
1211
libc::syscall(
1312
libc::SYS_getrandom,
1413
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
1514
buf.len(),
1615
0,
17-
) as libc::ssize_t
18-
}
16+
)
17+
};
18+
19+
const _: () =
20+
assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<libc::ssize_t>());
21+
res.try_into()
22+
.expect("c_long to ssize_t conversion is lossless")
1923
}

src/netbsd.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,18 @@ unsafe extern "C" fn polyfill_using_kern_arand(
1919
) -> libc::ssize_t {
2020
debug_assert_eq!(flags, 0);
2121

22-
static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND];
22+
const MIB_LEN: libc::c_uint = 2;
23+
static MIB: [libc::c_int; MIB_LEN as usize] = [libc::CTL_KERN, libc::KERN_ARND];
2324

2425
// NetBSD will only return up to 256 bytes at a time, and
2526
// older NetBSD kernels will fail on longer buffers.
2627
let mut len = cmp::min(buflen, 256);
2728

28-
let ret = unsafe {
29-
libc::sysctl(
30-
MIB.as_ptr(),
31-
MIB.len() as libc::c_uint,
32-
buf,
33-
&mut len,
34-
ptr::null(),
35-
0,
36-
)
37-
};
29+
let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) };
3830
if ret == -1 {
3931
-1
4032
} else {
41-
len as libc::ssize_t
33+
libc::ssize_t::try_from(len).expect("len is bounded by 256")
4234
}
4335
}
4436

src/util_libc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ pub fn sys_fill_exact(
5656
while !buf.is_empty() {
5757
let res = sys_fill(buf);
5858
match res {
59-
res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
59+
res if res > 0 => {
60+
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
61+
buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?;
62+
}
6063
-1 => {
6164
let err = last_os_error();
6265
// We should try again if the call was interrupted.

src/vxworks.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
2525
// Prevent overflow of i32
2626
let chunk_size = usize::try_from(i32::MAX).expect("VxWorks does not support 16-bit targets");
2727
for chunk in dest.chunks_mut(chunk_size) {
28-
let ret = unsafe { libc::randABytes(chunk.as_mut_ptr().cast::<u8>(), chunk.len() as i32) };
28+
let chunk_len: libc::c_int = chunk
29+
.len()
30+
.try_into()
31+
.expect("chunk size is bounded by i32::MAX");
32+
let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast();
33+
let ret = unsafe { libc::randABytes(p, chunk_len) };
2934
if ret != 0 {
3035
return Err(last_os_error());
3136
}

src/wasi.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
2424
// https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2046-2062
2525
// Note that size of an allocated object can not be bigger than isize::MAX bytes.
2626
// WASI 0.1 supports only 32-bit WASM, so casting length to `i32` is safe.
27+
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
2728
let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) };
2829
match ret {
2930
0 => Ok(()),
30-
_ => Err(Error::from_os_error(ret as u32)),
31+
code => {
32+
let err = u32::try_from(code)
33+
.map(Error::from_os_error)
34+
.unwrap_or(Error::UNEXPECTED);
35+
Err(err)
36+
}
3137
}
3238
}
3339

src/windows7.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
2727
// Prevent overflow of u32
2828
let chunk_size = usize::try_from(i32::MAX).expect("Windows does not support 16-bit targets");
2929
for chunk in dest.chunks_mut(chunk_size) {
30-
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::<c_void>(), chunk.len() as u32) };
30+
let chunk_len = u32::try_from(chunk.len()).expect("chunk size is bounded by i32::MAX");
31+
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::<c_void>(), chunk_len) };
3132
if ret != TRUE {
3233
return Err(Error::WINDOWS_RTL_GEN_RANDOM);
3334
}

0 commit comments

Comments
 (0)