From b9cca59ff7a817be0a0e4d53cd99cc4b3640afec Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 4 Jul 2019 17:41:04 -0700 Subject: [PATCH] Improve Error handling --- Cargo.toml | 1 + src/cloudabi.rs | 18 ++-- src/dummy.rs | 16 ++-- src/error.rs | 93 -------------------- src/error_impls.rs | 26 +----- src/freebsd.rs | 11 +-- src/fuchsia.rs | 17 ++-- src/ios.rs | 14 +-- src/lib.rs | 193 +++++++++++++++++++---------------------- src/linux_android.rs | 12 +-- src/macos.rs | 12 +-- src/openbsd_bitrig.rs | 11 +-- src/rdrand.rs | 16 ++-- src/solaris_illumos.rs | 12 +-- src/use_file.rs | 10 +-- src/util.rs | 18 ++++ src/wasi.rs | 13 ++- src/wasm32_bindgen.rs | 28 ++---- src/wasm32_stdweb.rs | 15 ++-- src/windows.rs | 14 +-- 20 files changed, 184 insertions(+), 366 deletions(-) delete mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index 2e6a93a5..2b813cc1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = ["tests/wasm_bindgen"] [dependencies] log = { version = "0.4", optional = true } +cfg-if = "0.1" [target.'cfg(any(unix, target_os = "redox", target_os = "wasi"))'.dependencies] libc = "0.2.54" diff --git a/src/cloudabi.rs b/src/cloudabi.rs index e87359ee..33040080 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -7,8 +7,11 @@ // except according to those terms. //! Implementation for CloudABI -use crate::Error; -use core::num::NonZeroU32; +extern crate std; + +use std::io; + +pub type Error = io::Error; extern "C" { fn cloudabi_sys_random_get(buf: *mut u8, buf_len: usize) -> u16; @@ -16,15 +19,10 @@ extern "C" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let errno = unsafe { cloudabi_sys_random_get(dest.as_mut_ptr(), dest.len()) }; - if let Some(code) = NonZeroU32::new(errno as u32) { - error!("cloudabi_sys_random_get failed with code {}", code); - Err(Error::from(code)) + if errno != 0 { + error!("cloudabi_sys_random_get failed with code {}", errno); + Err(Error::from_raw_os_error(errno as i32)) } else { Ok(()) // Zero means success for CloudABI } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/dummy.rs b/src/dummy.rs index b53f66c1..6734d07c 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -6,17 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A dummy implementation for unsupported targets which always returns -//! `Err(Error::UNAVAILABLE)` -use crate::Error; -use core::num::NonZeroU32; +//! A dummy implementation for unsupported targets which always fails. +use crate::util::StaticError; -pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { - error!("no support for this platform"); - Err(Error::UNAVAILABLE) -} +pub type Error = StaticError; -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None +pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { + Err(StaticError("getrandom: this target is not supported")) } diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 7ee27fd3..00000000 --- a/src/error.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -use core::convert::From; -use core::fmt; -use core::num::NonZeroU32; - -// A randomly-chosen 24-bit prefix for our codes -pub(crate) const CODE_PREFIX: u32 = 0x57f4c500; -const CODE_UNKNOWN: u32 = CODE_PREFIX | 0x00; -const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 0x01; - -/// The error type. -/// -/// This type is small and no-std compatible. -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Error(pub(crate) NonZeroU32); - -impl Error { - /// An unknown error. - pub const UNKNOWN: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNKNOWN) }); - - /// No generator is available. - pub const UNAVAILABLE: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); - - /// Extract the error code. - /// - /// This may equal one of the codes defined in this library or may be a - /// system error code. - /// - /// One may attempt to format this error via the `Display` implementation. - pub fn code(&self) -> NonZeroU32 { - self.0 - } - - pub(crate) fn msg(&self) -> Option<&'static str> { - if let Some(msg) = super::error_msg_inner(self.0) { - Some(msg) - } else { - match *self { - Error::UNKNOWN => Some("getrandom: unknown error"), - Error::UNAVAILABLE => Some("getrandom: unavailable"), - _ => None, - } - } - } -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.msg() { - Some(msg) => write!(f, "Error(\"{}\")", msg), - None => write!(f, "Error(0x{:08X})", self.0), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.msg() { - Some(msg) => write!(f, "{}", msg), - None => write!(f, "getrandom: unknown code 0x{:08X}", self.0), - } - } -} - -impl From for Error { - fn from(code: NonZeroU32) -> Self { - Error(code) - } -} - -impl From<&Error> for Error { - fn from(error: &Error) -> Self { - *error - } -} - -#[cfg(test)] -mod tests { - use super::Error; - use core::mem::size_of; - - #[test] - fn test_size() { - assert_eq!(size_of::(), 4); - assert_eq!(size_of::>(), 4); - } -} diff --git a/src/error_impls.rs b/src/error_impls.rs index 6bd2c69a..d2808dbd 100644 --- a/src/error_impls.rs +++ b/src/error_impls.rs @@ -5,30 +5,12 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate std; +use crate::Error; -use crate::error::Error; -use core::convert::From; -use core::num::NonZeroU32; -use std::{error, io}; - -impl From for Error { - fn from(err: io::Error) -> Self { - err.raw_os_error() - .and_then(|code| NonZeroU32::new(code as u32)) - .map(|code| Error(code)) - // in practice this should never happen - .unwrap_or(Error::UNKNOWN) - } -} - -impl From for io::Error { +impl From for std::io::Error { fn from(err: Error) -> Self { - match err.msg() { - Some(msg) => io::Error::new(io::ErrorKind::Other, msg), - None => io::Error::from_raw_os_error(err.0.get() as i32), - } + err.0.into() } } -impl error::Error for Error {} +impl std::error::Error for Error {} diff --git a/src/freebsd.rs b/src/freebsd.rs index 3a8ab609..abfbebe3 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -9,11 +9,11 @@ //! Implementation for FreeBSD extern crate std; -use crate::Error; -use core::num::NonZeroU32; use core::ptr; use std::io; +pub type Error = io::Error; + fn kern_arnd(buf: &mut [u8]) -> Result { static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; let mut len = buf.len(); @@ -29,7 +29,7 @@ fn kern_arnd(buf: &mut [u8]) -> Result { }; if ret == -1 { error!("freebsd: kern.arandom syscall failed"); - return Err(io::Error::last_os_error().into()); + return Err(Error::last_os_error()); } Ok(len) } @@ -41,8 +41,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/fuchsia.rs b/src/fuchsia.rs index a9f53888..ba784f0d 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -7,8 +7,16 @@ // except according to those terms. //! Implementation for Fuchsia Zircon -use crate::Error; -use core::num::NonZeroU32; +use core::convert::Infallible; + +pub type Error = Infallible; // Zircon's RNG cannot fail + +#[cfg(feature = "std")] +impl From for std::io::Error { + fn from(err: Error) -> Self { + match err {} + } +} #[link(name = "zircon")] extern "C" { @@ -19,8 +27,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { unsafe { zx_cprng_draw(dest.as_mut_ptr(), dest.len()) } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/ios.rs b/src/ios.rs index ed7f2cf1..5c0d312e 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -7,11 +7,9 @@ // except according to those terms. //! Implementation for iOS -extern crate std; +use crate::util::StaticError; -use crate::Error; -use core::num::NonZeroU32; -use std::io; +pub type Error = StaticError; // TODO: Make extern once extern_types feature is stabilized. See: // https://github.com/rust-lang/rust/issues/43467 @@ -28,14 +26,8 @@ extern "C" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) }; if ret == -1 { - error!("SecRandomCopyBytes call failed"); - Err(io::Error::last_os_error().into()) + Err(StaticError("SecRandomCopyBytes: call failed")) } else { Ok(()) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/lib.rs b/src/lib.rs index e279baa5..2270260b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,51 +127,32 @@ #![no_std] #![cfg_attr(feature = "stdweb", recursion_limit = "128")] -#[cfg(feature = "log")] +use core::fmt; #[macro_use] -extern crate log; -#[cfg(not(feature = "log"))] -#[allow(unused)] -macro_rules! error { - ($($x:tt)*) => {}; +extern crate cfg_if; + +cfg_if! { + if #[cfg(feature = "log")] { + #[allow(unused)] + #[macro_use] + extern crate log; + } else { + #[allow(unused)] + macro_rules! error { + ($($x:tt)*) => {}; + } + } } -// temp fix for stdweb -#[cfg(target_arch = "wasm32")] +#[cfg(feature = "std")] extern crate std; -mod error; -pub use crate::error::Error; - #[allow(dead_code)] mod util; #[cfg(any(unix, target_os = "redox"))] #[allow(dead_code)] mod util_libc; -// System-specific implementations. -// -// These should all provide getrandom_inner with the same signature as getrandom. - -macro_rules! mod_use { - ($cond:meta, $module:ident) => { - #[$cond] - mod $module; - #[$cond] - use crate::$module::{error_msg_inner, getrandom_inner}; - }; -} - -// These targets use std anyway, so we use the std declarations. -#[cfg(any( - feature = "std", - windows, - unix, - target_os = "redox", - target_arch = "wasm32", -))] -mod error_impls; - // These targets read from a file as a fallback method. #[cfg(any( target_os = "android", @@ -180,79 +161,83 @@ mod error_impls; target_os = "solaris", target_os = "illumos", ))] +#[allow(dead_code)] mod use_file; -mod_use!(cfg(target_os = "android"), linux_android); -mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig); -mod_use!(cfg(target_os = "cloudabi"), cloudabi); -mod_use!(cfg(target_os = "dragonfly"), use_file); -mod_use!(cfg(target_os = "emscripten"), use_file); -mod_use!(cfg(target_os = "freebsd"), freebsd); -mod_use!(cfg(target_os = "fuchsia"), fuchsia); -mod_use!(cfg(target_os = "haiku"), use_file); -mod_use!(cfg(target_os = "illumos"), solaris_illumos); -mod_use!(cfg(target_os = "ios"), ios); -mod_use!(cfg(target_os = "linux"), linux_android); -mod_use!(cfg(target_os = "macos"), macos); -mod_use!(cfg(target_os = "netbsd"), use_file); -mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); -mod_use!(cfg(target_os = "redox"), use_file); -mod_use!(cfg(target_os = "solaris"), solaris_illumos); -mod_use!(cfg(windows), windows); -mod_use!(cfg(target_env = "sgx"), rdrand); -mod_use!(cfg(all(target_arch = "x86_64", target_os = "uefi")), rdrand); -mod_use!(cfg(target_os = "wasi"), wasi); +// System-specific implementations. +// +// These files should provide a getrandom_inner function and an Error type. +cfg_if! { + if #[cfg(target_os = "android")] { + #[path = "linux_android.rs"] mod imp; + } else if #[cfg(target_os = "bitrig")] { + #[path = "openbsd_bitrig.rs"] mod imp; + } else if #[cfg(target_os = "cloudabi")] { + #[path = "cloudabi.rs"] mod imp; + } else if #[cfg(target_os = "dragonfly")] { + #[path = "use_file.rs"] mod imp; + } else if #[cfg(target_os = "emscripten")] { + #[path = "use_file.rs"] mod imp; + } else if #[cfg(target_os = "freebsd")] { + #[path = "freebsd.rs"] mod imp; + } else if #[cfg(target_os = "fuchsia")] { + #[path = "fuchsia.rs"] mod imp; + } else if #[cfg(target_os = "haiku")] { + #[path = "use_file.rs"] mod imp; + } else if #[cfg(target_os = "illumos")] { + #[path = "solaris_illumos.rs"] mod imp; + } else if #[cfg(target_os = "ios")] { + #[path = "ios.rs"] mod imp; + } else if #[cfg(target_os = "linux")] { + #[path = "linux_android.rs"] mod imp; + } else if #[cfg(target_os = "macos")] { + #[path = "macos.rs"] mod imp; + } else if #[cfg(target_os = "netbsd")] { + #[path = "use_file.rs"] mod imp; + } else if #[cfg(target_os = "openbsd")] { + #[path = "openbsd_bitrig.rs"] mod imp; + } else if #[cfg(target_os = "redox")] { + #[path = "use_file.rs"] mod imp; + } else if #[cfg(target_os = "solaris")] { + #[path = "solaris_illumos.rs"] mod imp; + } else if #[cfg(target_os = "wasi")] { + #[path = "wasi.rs"] mod imp; + } else if #[cfg(windows)] { + #[path = "windows.rs"] mod imp; + } else if #[cfg(target_env = "sgx")] { + #[path = "rdrand.rs"] mod imp; + } else if #[cfg(all(target_arch = "x86_64", target_os = "uefi"))] { + #[path = "rdrand.rs"] mod imp; + } else if #[cfg(target_arch = "wasm32")] { + cfg_if! { + if #[cfg(feature = "wasm-bindgen")] { + #[path = "wasm32_bindgen.rs"] mod imp; + } else if #[cfg(feature = "stdweb")] { + // temp fix for stdweb + extern crate std; + #[path = "wasm32_stdweb.rs"] mod imp; + } else { + #[path = "dummy.rs"] mod imp; + } + } + } else { + #[path = "dummy.rs"] mod imp; + } +} -mod_use!( - cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - not(target_os = "wasi"), - feature = "wasm-bindgen" - )), - wasm32_bindgen -); +/// Opaque error type returned by getrandom. +#[derive(Debug)] +pub struct Error(imp::Error); -mod_use!( - cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - not(target_os = "wasi"), - not(feature = "wasm-bindgen"), - feature = "stdweb", - )), - wasm32_stdweb -); +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} -mod_use!( - cfg(not(any( - target_os = "android", - target_os = "bitrig", - target_os = "cloudabi", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox", - target_os = "solaris", - all(target_arch = "x86_64", target_os = "uefi"), - target_os = "wasi", - target_env = "sgx", - windows, - all( - target_arch = "wasm32", - any(feature = "wasm-bindgen", feature = "stdweb"), - ), - ))), - dummy -); +// std-only trait definitions +#[cfg(feature = "std")] +mod error_impls; /// Fill `dest` with random bytes from the system's preferred random number /// source. @@ -265,6 +250,6 @@ mod_use!( /// In general, `getrandom` will be fast enough for interactive usage, though /// significantly slower than a user-space CSPRNG; for the latter consider /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). -pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> { - getrandom_inner(dest) +pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { + imp::getrandom_inner(dest).map_err(|e| Error(e)) } diff --git a/src/linux_android.rs b/src/linux_android.rs index d7c046da..666f5b0b 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -9,16 +9,17 @@ //! Implementation for Linux / Android extern crate std; +use crate::use_file; use crate::util::LazyBool; -use crate::{use_file, Error}; -use core::num::NonZeroU32; use std::io; +pub type Error = io::Error; + fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result { let flags = if block { 0 } else { libc::GRND_NONBLOCK }; let ret = unsafe { libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), flags) }; if ret < 0 { - let err = io::Error::last_os_error(); + let err = Error::last_os_error(); if err.raw_os_error() == Some(libc::EINTR) { return Ok(0); // Call was interrupted, try again } @@ -51,8 +52,3 @@ fn is_getrandom_available() -> bool { Ok(_) => true, } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/macos.rs b/src/macos.rs index 84d95565..be23b2d8 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -9,12 +9,13 @@ //! Implementation for macOS extern crate std; +use crate::use_file; use crate::util_libc::Weak; -use crate::{use_file, Error}; use core::mem; -use core::num::NonZeroU32; use std::io; +pub type Error = io::Error; + type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { @@ -25,7 +26,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) }; if ret != 0 { error!("getentropy syscall failed with ret={}", ret); - return Err(io::Error::last_os_error().into()); + return Err(Error::last_os_error()); } } Ok(()) @@ -35,8 +36,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { use_file::getrandom_inner(dest) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/openbsd_bitrig.rs b/src/openbsd_bitrig.rs index 24e5c191..d6f54db4 100644 --- a/src/openbsd_bitrig.rs +++ b/src/openbsd_bitrig.rs @@ -9,22 +9,17 @@ //! Implementation for OpenBSD / Bitrig extern crate std; -use crate::Error; -use core::num::NonZeroU32; use std::io; +pub type Error = io::Error; + pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; if ret == -1 { error!("libc::getentropy call failed"); - return Err(io::Error::last_os_error().into()); + return Err(Error::last_os_error()); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/rdrand.rs b/src/rdrand.rs index 12843735..ff3999d2 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -7,11 +7,13 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction +#[cfg(not(target_feature = "rdrand"))] use crate::util::LazyBool; -use crate::Error; +use crate::util::StaticError; use core::arch::x86_64::_rdrand64_step; use core::mem; -use core::num::NonZeroU32; + +pub type Error = StaticError; // Recommendation from "IntelĀ® Digital Random Number Generator (DRNG) Software // Implementation Guide" - Section 5.2.1 and "IntelĀ® 64 and IA-32 Architectures @@ -36,8 +38,7 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> { // Keep looping in case this was a false positive. } } - error!("RDRAND failed, CPU issue likely"); - Err(Error::UNKNOWN) + Err(StaticError("RDRAND failed, CPU issue likely")) } // "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653. @@ -64,7 +65,7 @@ fn is_rdrand_supported() -> bool { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if !is_rdrand_supported() { - return Err(Error::UNAVAILABLE); + return Err(StaticError("RDRAND instruction not supported")); } // SAFETY: After this point, rdrand is supported, so calling the rdrand @@ -88,8 +89,3 @@ unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/solaris_illumos.rs b/src/solaris_illumos.rs index 9d629e40..741aca16 100644 --- a/src/solaris_illumos.rs +++ b/src/solaris_illumos.rs @@ -19,12 +19,13 @@ //! libc::dlsym. extern crate std; +use crate::use_file; use crate::util_libc::Weak; -use crate::{use_file, Error}; use core::mem; -use core::num::NonZeroU32; use std::io; +pub type Error = io::Error; + #[cfg(target_os = "illumos")] type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; #[cfg(target_os = "solaris")] @@ -40,7 +41,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len(), 0) }; if ret != chunk.len() as _ { error!("getrandom syscall failed with ret={}", ret); - return Err(io::Error::last_os_error().into()); + return Err(Error::last_os_error()); } } Ok(()) @@ -48,8 +49,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { use_file::getrandom_inner(dest) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/use_file.rs b/src/use_file.rs index adc1b3cd..0f66b3f7 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -10,15 +10,15 @@ extern crate std; use crate::util_libc::LazyFd; -use crate::Error; use core::mem::ManuallyDrop; -use core::num::NonZeroU32; use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; use std::{ fs::File, io::{self, Read}, }; +pub type Error = io::Error; + #[cfg(target_os = "redox")] const FILE_PATH: &str = "rand:"; #[cfg(any(target_os = "android", target_os = "linux", target_os = "netbsd"))] @@ -60,9 +60,3 @@ fn init_file() -> Option { } Some(File::open(FILE_PATH).ok()?.into_raw_fd()) } - -#[inline(always)] -#[allow(dead_code)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/util.rs b/src/util.rs index a0675be2..4e17acb6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -6,8 +6,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::fmt; use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +// An error type for platforms that can only fail in a fixed number of ways. +#[derive(Debug)] +pub struct StaticError(pub &'static str); + +impl fmt::Display for StaticError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.0) + } +} + +#[cfg(feature = "std")] +impl From for std::io::Error { + fn from(err: Error) -> Self { + Self::new(std::io::ErrorKind::Other, err) + } +} + // This structure represents a laziliy initialized static usize value. Useful // when it is perferable to just rerun initialization instead of locking. // Both unsync_init and sync_init will invoke an init() function until it diff --git a/src/wasi.rs b/src/wasi.rs index 3cc7e31b..dabf2b37 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -7,10 +7,12 @@ // except according to those terms. //! Implementation for WASI -use crate::Error; -use core::num::NonZeroU32; +extern crate std; + use std::io; +pub type Error = io::Error; + pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { libc::__wasi_random_get(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) }; @@ -18,11 +20,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { Ok(()) } else { error!("WASI: __wasi_random_get failed with return value {}", ret); - Err(io::Error::last_os_error().into()) + Err(Error::from_raw_os_error(ret as i32)) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 37a85afa..5bf42a87 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -7,18 +7,17 @@ // except according to those terms. //! Implementation for WASM via wasm-bindgen +extern crate std; + +use crate::util::StaticError; use core::cell::RefCell; +use core::fmt; use core::mem; -use core::num::NonZeroU32; use std::thread_local; use wasm_bindgen::prelude::*; -use crate::error::CODE_PREFIX; -use crate::Error; - -const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 0x80; -const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 0x81; +pub type Error = StaticError; #[derive(Clone, Debug)] enum RngSource { @@ -81,17 +80,13 @@ fn getrandom_init() -> Result { // we're in an older web browser and the OS RNG isn't available. let crypto = this.crypto(); if crypto.is_undefined() { - return Err(Error::from(unsafe { - NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF) - })); + return Err(StaticError("getrandom: self.crypto is undefined")); } // Test if `crypto.getRandomValues` is undefined as well let crypto: BrowserCrypto = crypto.into(); if crypto.get_random_values_fn().is_undefined() { - return Err(Error::from(unsafe { - NonZeroU32::new_unchecked(CODE_GRV_UNDEF) - })); + return Err(StaticError("crypto.getRandomValues is undefined")); } // Ok! `self.crypto.getRandomValues` is a defined value, so let's @@ -99,15 +94,6 @@ fn getrandom_init() -> Result { Ok(RngSource::Browser(crypto)) } -#[inline(always)] -pub fn error_msg_inner(n: NonZeroU32) -> Option<&'static str> { - match n.get() { - CODE_CRYPTO_UNDEF => Some("getrandom: self.crypto is undefined"), - CODE_GRV_UNDEF => Some("crypto.getRandomValues is undefined"), - _ => None, - } -} - #[wasm_bindgen] extern "C" { type Function; diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 32a5686c..c97439b6 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -8,15 +8,15 @@ //! Implementation for WASM via stdweb use core::mem; -use core::num::NonZeroU32; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; use stdweb::{_js_impl, js}; -use crate::Error; use std::sync::Once; +pub type Error = WebError; + #[derive(Clone, Copy, Debug)] enum RngSource { Browser, @@ -26,7 +26,7 @@ enum RngSource { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { assert_eq!(mem::size_of::(), 4); static ONCE: Once = Once::new(); - static mut RNG_SOURCE: Result = Err(Error::UNAVAILABLE); + static mut RNG_SOURCE: Result = Ok(RngSource::Browser); // SAFETY: RNG_SOURCE is only written once, before being read. ONCE.call_once(|| unsafe { @@ -69,7 +69,7 @@ fn getrandom_init() -> Result { } else { let err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom unavailable: {}", err); - Err(Error::UNAVAILABLE) + Err(err) } } @@ -105,13 +105,8 @@ fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> { if js! { return @{ result.as_ref() }.success } != true { let err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom failed: {}", err); - return Err(Error::UNKNOWN); + return Err(err); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/windows.rs b/src/windows.rs index f3f96d8c..92e346cf 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -7,11 +7,9 @@ // except according to those terms. //! Implementation for Windows -extern crate std; +use crate::util::StaticError; -use crate::Error; -use core::num::NonZeroU32; -use std::io; +pub type Error = StaticError; extern "system" { #[link_name = "SystemFunction036"] @@ -23,14 +21,8 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(u32::max_value() as usize) { let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) }; if ret == 0 { - error!("RtlGenRandom call failed"); - return Err(io::Error::last_os_error().into()); + return Err(StaticError("RtlGenRandom: call failed")); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -}