Skip to content

Commit a40f305

Browse files
committed
Tweak Error representation
1 parent 76ed428 commit a40f305

File tree

6 files changed

+59
-48
lines changed

6 files changed

+59
-48
lines changed

src/backends/hermit.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,8 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
4444
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
4545
}
4646
code => {
47-
let err = u32::try_from(code.unsigned_abs())
48-
.ok()
49-
.map_or(Error::UNEXPECTED, Error::from_os_error);
50-
return Err(err);
47+
let code = i32::try_from(code).map_err(|_| Error::UNEXPECTED)?;
48+
return Err(Error::from_os_error(code));
5149
}
5250
}
5351
}

src/backends/linux_raw.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,7 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
128128
}
129129
Err(_) if ret == EINTR => continue,
130130
Err(_) => {
131-
let code: u32 = ret
132-
.wrapping_neg()
133-
.try_into()
134-
.map_err(|_| Error::UNEXPECTED)?;
131+
let code = i32::try_from(ret).map_err(|_| Error::UNEXPECTED)?;
135132
return Err(Error::from_os_error(code));
136133
}
137134
}

src/backends/solid.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
1414
if ret >= 0 {
1515
Ok(())
1616
} else {
17-
// ITRON error numbers are always negative, so we negate it so that it
18-
// falls in the dedicated OS error range (1..INTERNAL_START).
19-
Err(Error::from_os_error(ret.unsigned_abs()))
17+
Err(Error::from_os_error(ret))
2018
}
2119
}

src/backends/wasi_p1.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
2121
let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) };
2222
match ret {
2323
0 => Ok(()),
24-
code => {
25-
let err = u32::try_from(code)
26-
.map(Error::from_os_error)
27-
.unwrap_or(Error::UNEXPECTED);
28-
Err(err)
29-
}
24+
code => Err(Error::from_os_error(code)),
3025
}
3126
}

src/error.rs

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#[cfg(feature = "std")]
22
extern crate std;
33

4-
use core::{fmt, num::NonZeroU32};
4+
use core::fmt;
55

66
// This private alias mirrors `std::io::RawOsError`:
77
// https://doc.rust-lang.org/std/io/type.RawOsError.html)
88
cfg_if::cfg_if!(
99
if #[cfg(target_os = "uefi")] {
1010
type RawOsError = usize;
11+
type NonZeroRawOsError = core::num::NonZeroUsize;
12+
const UEFI_ERROR_FLAG: RawOsError = 1 << (RawOsError::BITS - 1);
1113
} else {
1214
type RawOsError = i32;
15+
type NonZeroRawOsError = core::num::NonZeroI32;
1316
}
1417
);
1518

@@ -27,8 +30,10 @@ cfg_if::cfg_if!(
2730
/// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
2831
/// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements
2932
/// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html).
33+
// note: on non-UEFI targets OS errors are represented as negative integers,
34+
// while on UEFI targets OS errors have the highest bit set to 1.
3035
#[derive(Copy, Clone, Eq, PartialEq)]
31-
pub struct Error(NonZeroU32);
36+
pub struct Error(NonZeroRawOsError);
3237

3338
impl Error {
3439
/// This target/platform is not supported by `getrandom`.
@@ -38,28 +43,33 @@ impl Error {
3843
/// Encountered an unexpected situation which should not happen in practice.
3944
pub const UNEXPECTED: Error = Self::new_internal(2);
4045

41-
/// Codes below this point represent OS Errors (i.e. positive i32 values).
42-
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
43-
/// reserved for use by the `rand` and `getrandom` crates.
46+
/// Deprecated.
47+
#[deprecated]
4448
pub const INTERNAL_START: u32 = 1 << 31;
4549

46-
/// Codes at or above this point can be used by users to define their own
47-
/// custom errors.
50+
/// Deprecated.
51+
#[deprecated]
4852
pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
4953

54+
/// Internal errors can be in the range of 2^16..2^17
55+
const INTERNAL_START2: RawOsError = 1 << 16;
56+
/// Custom errors can be in the range of 2^17..(2^17 + 2^16)
57+
const CUSTOM_START2: RawOsError = 1 << 17;
58+
5059
/// Creates a new instance of an `Error` from a particular OS error code.
5160
///
5261
/// This method is analogous to [`std::io::Error::from_raw_os_error()`][1],
5362
/// except that it works in `no_std` contexts and `code` will be
54-
/// replaced with `Error::UNEXPECTED` if it isn't in the range
55-
/// `1..Error::INTERNAL_START`. Thus, for the result `r`,
56-
/// `r == Self::UNEXPECTED || r.raw_os_error().unsigned_abs() == code`.
63+
/// replaced with `Error::UNEXPECTED` in unexpected cases.
5764
///
5865
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.from_raw_os_error
5966
#[allow(dead_code)]
60-
pub(super) fn from_os_error(code: u32) -> Self {
61-
match NonZeroU32::new(code) {
62-
Some(code) if code.get() < Self::INTERNAL_START => Self(code),
67+
pub(super) fn from_os_error(code: RawOsError) -> Self {
68+
match NonZeroRawOsError::new(code) {
69+
#[cfg(target_os = "uefi")]
70+
Some(code) if code.get() & UEFI_ERROR_FLAG != 0 => Self(code),
71+
#[cfg(not(target_os = "uefi"))]
72+
Some(code) if code.get() < 0 => Self(code),
6373
_ => Self::UNEXPECTED,
6474
}
6575
}
@@ -79,27 +89,38 @@ impl Error {
7989
#[inline]
8090
pub fn raw_os_error(self) -> Option<RawOsError> {
8191
let code = self.0.get();
82-
if code >= Self::INTERNAL_START {
83-
return None;
92+
#[cfg(target_os = "uefi")]
93+
{
94+
if code & UEFI_ERROR_FLAG != 0 {
95+
Some(code)
96+
} else {
97+
None
98+
}
99+
}
100+
101+
#[cfg(not(target_os = "uefi"))]
102+
{
103+
if code >= 0 {
104+
return None;
105+
}
106+
#[cfg(not(target_os = "solid_asp3"))]
107+
let code = code.checked_neg()?;
108+
Some(code)
84109
}
85-
let errno = RawOsError::try_from(code).ok()?;
86-
#[cfg(target_os = "solid_asp3")]
87-
let errno = -errno;
88-
Some(errno)
89110
}
90111

91112
/// Creates a new instance of an `Error` from a particular custom error code.
92113
pub const fn new_custom(n: u16) -> Error {
93-
// SAFETY: code > 0 as CUSTOM_START > 0 and adding n won't overflow a u32.
94-
let code = Error::CUSTOM_START + (n as u32);
95-
Error(unsafe { NonZeroU32::new_unchecked(code) })
114+
// SAFETY: code > 0 as CUSTOM_START > 0 and adding `n` won't overflow `RawOsError`.
115+
let code = Error::CUSTOM_START2 + (n as RawOsError);
116+
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
96117
}
97118

98119
/// Creates a new instance of an `Error` from a particular internal error code.
99120
pub(crate) const fn new_internal(n: u16) -> Error {
100-
// SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32.
101-
let code = Error::INTERNAL_START + (n as u32);
102-
Error(unsafe { NonZeroU32::new_unchecked(code) })
121+
// SAFETY: code > 0 as INTERNAL_START > 0 and adding `n` won't overflow `RawOsError`.
122+
let code = Error::INTERNAL_START2 + (n as RawOsError);
123+
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
103124
}
104125

105126
fn internal_desc(&self) -> Option<&'static str> {

src/util_libc.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ cfg_if! {
3434
}
3535

3636
pub(crate) fn last_os_error() -> Error {
37+
// We assum that on all targets which use this function `c_int` is equal to `i32`
3738
let errno: libc::c_int = unsafe { get_errno() };
3839

39-
// c_int-to-u32 conversion is lossless for nonnegative values if they are the same size.
40-
const _: () = assert!(core::mem::size_of::<libc::c_int>() == core::mem::size_of::<u32>());
41-
42-
match u32::try_from(errno) {
43-
Ok(code) if code != 0 => Error::from_os_error(code),
44-
_ => Error::ERRNO_NOT_POSITIVE,
40+
if errno > 0 {
41+
let code = errno
42+
.checked_neg()
43+
.expect("Positive number can be always negated");
44+
Error::from_os_error(code)
45+
} else {
46+
Error::ERRNO_NOT_POSITIVE
4547
}
4648
}
4749

0 commit comments

Comments
 (0)