diff --git a/.clippy.toml b/.clippy.toml deleted file mode 100644 index 13f202e9..00000000 --- a/.clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.60" diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index a230e1c9..13dba99a 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2024-09-04 + toolchain: nightly-2024-10-08 components: clippy,rust-src - name: std feature run: cargo clippy --features std diff --git a/src/error.rs b/src/error.rs index 1c158439..d0299267 100644 --- a/src/error.rs +++ b/src/error.rs @@ -88,18 +88,14 @@ impl Error { /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error #[inline] pub fn raw_os_error(self) -> Option { - if self.0.get() < Self::INTERNAL_START { - match () { - #[cfg(target_os = "solid_asp3")] - // On SOLID, negate the error code again to obtain the original - // error code. - () => Some(-(self.0.get() as i32)), - #[cfg(not(target_os = "solid_asp3"))] - () => Some(self.0.get() as i32), + i32::try_from(self.0.get()).ok().map(|errno| { + // On SOLID, negate the error code again to obtain the original error code. + if cfg!(target_os = "solid_asp3") { + -errno + } else { + errno } - } else { - None - } + }) } /// Creates a new instance of an `Error` from a particular custom error code. diff --git a/src/hermit.rs b/src/hermit.rs index c869372a..9dc9d8bd 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -9,18 +9,17 @@ extern "C" { pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::(), dest.len(), 0) }; - // Positive `isize`s can be safely casted to `usize` - if res > 0 && (res as usize) <= dest.len() { - dest = &mut dest[res as usize..]; - } else { - let err = if res < 0 { - u32::try_from(res.unsigned_abs()) + match res { + res if res > 0 => { + let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?; + dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?; + } + code => { + let err = u32::try_from(code.unsigned_abs()) .ok() - .map_or(Error::UNEXPECTED, Error::from_os_error) - } else { - Error::UNEXPECTED - }; - return Err(err); + .map_or(Error::UNEXPECTED, Error::from_os_error); + return Err(err); + } } } Ok(()) diff --git a/src/js.rs b/src/js.rs index bec31ee5..65f63a1a 100644 --- a/src/js.rs +++ b/src/js.rs @@ -9,7 +9,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; // Size of our temporary Uint8Array buffer used with WebCrypto methods // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -const WEB_CRYPTO_BUFFER_SIZE: usize = 256; +const WEB_CRYPTO_BUFFER_SIZE: u16 = 256; // Node.js's crypto.randomFillSync requires the size to be less than 2**31. const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1; @@ -50,10 +50,14 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> RngSource::Web(crypto, buf) => { // getRandomValues does not work with all types of WASM memory, // so we initially write to browser memory to avoid exceptions. - for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE) { + for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE.into()) { + let chunk_len: u32 = chunk + .len() + .try_into() + .expect("chunk length is bounded by WEB_CRYPTO_BUFFER_SIZE"); // The chunk can be smaller than buf's length, so we call to // JS to create a smaller view of buf without allocation. - let sub_buf = buf.subarray(0, chunk.len() as u32); + let sub_buf = buf.subarray(0, chunk_len); if crypto.get_random_values(&sub_buf).is_err() { return Err(Error::WEB_GET_RANDOM_VALUES); @@ -95,7 +99,7 @@ fn getrandom_init() -> Result { }, }; - let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE as u32); + let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into()); Ok(RngSource::Web(crypto, buf)) } diff --git a/src/lib.rs b/src/lib.rs index 07d4be22..5cc40941 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,21 @@ #![no_std] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![deny( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_ptr_alignment, + clippy::cast_sign_loss, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::fn_to_numeric_cast, + clippy::fn_to_numeric_cast_with_truncation, + clippy::ptr_as_ptr, + clippy::unnecessary_cast, + clippy::useless_conversion +)] #[macro_use] extern crate cfg_if; diff --git a/src/linux_android.rs b/src/linux_android.rs index 7c1fede4..401d3dfc 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -6,14 +6,18 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, getrandom_syscall) } -// Also used by linux_android_with_fallback to check if the syscall is available. pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { - unsafe { + let res: libc::c_long = unsafe { libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr().cast::(), buf.len(), 0, - ) as libc::ssize_t - } + ) + }; + + const _: () = + assert!(core::mem::size_of::() == core::mem::size_of::()); + res.try_into() + .expect("c_long to ssize_t conversion is lossless") } diff --git a/src/netbsd.rs b/src/netbsd.rs index 2842617b..93469ee9 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -19,26 +19,18 @@ unsafe extern "C" fn polyfill_using_kern_arand( ) -> libc::ssize_t { debug_assert_eq!(flags, 0); - static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; + const MIB_LEN: libc::c_uint = 2; + static MIB: [libc::c_int; MIB_LEN as usize] = [libc::CTL_KERN, libc::KERN_ARND]; // NetBSD will only return up to 256 bytes at a time, and // older NetBSD kernels will fail on longer buffers. let mut len = cmp::min(buflen, 256); - let ret = unsafe { - libc::sysctl( - MIB.as_ptr(), - MIB.len() as libc::c_uint, - buf, - &mut len, - ptr::null(), - 0, - ) - }; + let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) }; if ret == -1 { -1 } else { - len as libc::ssize_t + libc::ssize_t::try_from(len).expect("len is bounded by 256") } } diff --git a/src/util_libc.rs b/src/util_libc.rs index 7708bfcc..4b33b8cd 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -56,7 +56,10 @@ pub fn sys_fill_exact( while !buf.is_empty() { let res = sys_fill(buf); match res { - res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?, + res if res > 0 => { + let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?; + buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?; + } -1 => { let err = last_os_error(); // We should try again if the call was interrupted. diff --git a/src/vxworks.rs b/src/vxworks.rs index 7f0613d2..58b6c962 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -25,7 +25,12 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of i32 let chunk_size = usize::try_from(i32::MAX).expect("VxWorks does not support 16-bit targets"); for chunk in dest.chunks_mut(chunk_size) { - let ret = unsafe { libc::randABytes(chunk.as_mut_ptr().cast::(), chunk.len() as i32) }; + let chunk_len: libc::c_int = chunk + .len() + .try_into() + .expect("chunk size is bounded by i32::MAX"); + let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast(); + let ret = unsafe { libc::randABytes(p, chunk_len) }; if ret != 0 { return Err(last_os_error()); } diff --git a/src/wasi.rs b/src/wasi.rs index db2a800e..9df9bf26 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -24,10 +24,16 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2046-2062 // Note that size of an allocated object can not be bigger than isize::MAX bytes. // WASI 0.1 supports only 32-bit WASM, so casting length to `i32` is safe. + #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) }; match ret { 0 => Ok(()), - _ => Err(Error::from_os_error(ret as u32)), + code => { + let err = u32::try_from(code) + .map(Error::from_os_error) + .unwrap_or(Error::UNEXPECTED); + Err(err) + } } } diff --git a/src/windows7.rs b/src/windows7.rs index 6714f66b..667bbf26 100644 --- a/src/windows7.rs +++ b/src/windows7.rs @@ -27,7 +27,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of u32 let chunk_size = usize::try_from(i32::MAX).expect("Windows does not support 16-bit targets"); for chunk in dest.chunks_mut(chunk_size) { - let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) }; + let chunk_len = u32::try_from(chunk.len()).expect("chunk size is bounded by i32::MAX"); + let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk_len) }; if ret != TRUE { return Err(Error::WINDOWS_RTL_GEN_RANDOM); }