Skip to content

Commit

Permalink
Replace more casts with safer conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Oct 9, 2024
1 parent 74e2391 commit 3d16230
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 32 deletions.
18 changes: 7 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32> {
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.
Expand Down
22 changes: 11 additions & 11 deletions src/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ extern "C" {
pub fn getrandom_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
while !dest.is_empty() {
let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::<u8>(), 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)?;
}
0 => 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(())
Expand Down
12 changes: 8 additions & 4 deletions src/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -50,10 +50,14 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> 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);
Expand Down Expand Up @@ -95,7 +99,7 @@ fn getrandom_init() -> Result<RngSource, Error> {
},
};

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))
}

Expand Down
12 changes: 8 additions & 4 deletions src/linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> 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<u8>]) -> libc::ssize_t {
unsafe {
let res: libc::c_long = unsafe {
libc::syscall(
libc::SYS_getrandom,
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
buf.len(),
0,
) as libc::ssize_t
}
)
};

const _: () =
assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<libc::ssize_t>());
res.try_into()
.expect("c_long to ssize_t conversion is lossless")
}
5 changes: 4 additions & 1 deletion src/util_libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion src/windows7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> 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::<c_void>(), 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::<c_void>(), chunk_len) };
if ret != TRUE {
return Err(Error::WINDOWS_RTL_GEN_RANDOM);
}
Expand Down

0 comments on commit 3d16230

Please sign in to comment.