From bd52e3818847d848501f64ccab1f8e39a860816e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 24 Nov 2025 16:13:19 -0500 Subject: [PATCH] Avoid conditional module inclusion This requires slightly more logic in util_libc, but produces a more typical setup for the crate. --- src/backends/getentropy.rs | 5 +- src/backends/getrandom.rs | 5 +- src/backends/linux_android_with_fallback.rs | 3 +- src/backends/netbsd.rs | 5 +- src/backends/rdrand.rs | 10 +- src/backends/rndr.rs | 3 +- src/backends/solaris.rs | 5 +- src/backends/use_file.rs | 5 +- src/backends/vxworks.rs | 5 +- src/error.rs | 2 - src/lib.rs | 5 + src/util.rs | 1 - src/util_libc.rs | 150 +++++++++++--------- 13 files changed, 97 insertions(+), 107 deletions(-) diff --git a/src/backends/getentropy.rs b/src/backends/getentropy.rs index ed181f019..7d88f2958 100644 --- a/src/backends/getentropy.rs +++ b/src/backends/getentropy.rs @@ -7,14 +7,11 @@ //! - vita newlib since Dec 2021 //! //! For these targets, we use getentropy(2) because getrandom(2) doesn't exist. -use crate::Error; +use crate::{Error, util_libc}; use core::{ffi::c_void, mem::MaybeUninit}; pub use crate::util::{inner_u32, inner_u64}; -#[path = "../util_libc.rs"] -mod util_libc; - #[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { diff --git a/src/backends/getrandom.rs b/src/backends/getrandom.rs index af97eab28..44948c84d 100644 --- a/src/backends/getrandom.rs +++ b/src/backends/getrandom.rs @@ -15,14 +15,11 @@ //! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does //! nothing. On illumos, the default pool is used to implement getentropy(2), //! so we assume it is acceptable here. -use crate::Error; +use crate::{Error, util_libc}; use core::mem::MaybeUninit; pub use crate::util::{inner_u32, inner_u64}; -#[path = "../util_libc.rs"] -mod util_libc; - #[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| { diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index d4ae6f247..c69dea2f8 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -1,13 +1,12 @@ //! Implementation for Linux / Android with `/dev/urandom` fallback use super::{sanitizer, use_file}; -use crate::Error; +use crate::{Error, util_libc}; use core::{ ffi::c_void, mem::{MaybeUninit, transmute}, ptr::NonNull, sync::atomic::{AtomicPtr, Ordering}, }; -use use_file::util_libc; pub use crate::util::{inner_u32, inner_u64}; diff --git a/src/backends/netbsd.rs b/src/backends/netbsd.rs index f228a8b13..9987db199 100644 --- a/src/backends/netbsd.rs +++ b/src/backends/netbsd.rs @@ -3,7 +3,7 @@ //! `getrandom(2)` was introduced in NetBSD 10. To support older versions we //! implement our own weak linkage to it, and provide a fallback based on the //! KERN_ARND sysctl. -use crate::Error; +use crate::{Error, util_libc}; use core::{ cmp, ffi::c_void, @@ -14,9 +14,6 @@ use core::{ pub use crate::util::{inner_u32, inner_u64}; -#[path = "../util_libc.rs"] -mod util_libc; - unsafe extern "C" fn polyfill_using_kern_arand( buf: *mut c_void, buflen: libc::size_t, diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index e1e8934cb..e29baca33 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -1,13 +1,7 @@ //! RDRAND backend for x86(-64) targets -use crate::{Error, util::slice_as_uninit}; +use crate::{Error, lazy, util::slice_as_uninit}; use core::mem::{MaybeUninit, size_of}; -#[path = "../lazy.rs"] -mod lazy; - -#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] -compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!"); - cfg_if! { if #[cfg(target_arch = "x86_64")] { use core::arch::x86_64 as arch; @@ -17,6 +11,8 @@ cfg_if! { use core::arch::x86 as arch; use arch::_rdrand32_step as rdrand_step; type Word = u32; + } else { + compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!"); } } diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index 0b0636aea..2f048e811 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -69,8 +69,7 @@ fn is_rndr_available() -> bool { #[cfg(not(target_feature = "rand"))] fn is_rndr_available() -> bool { - #[path = "../lazy.rs"] - mod lazy; + use crate::lazy; static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); cfg_if::cfg_if! { diff --git a/src/backends/solaris.rs b/src/backends/solaris.rs index c27f91a5f..547bd8594 100644 --- a/src/backends/solaris.rs +++ b/src/backends/solaris.rs @@ -12,14 +12,11 @@ //! For more information, see the man page linked in lib.rs and this blog post: //! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 //! which also explains why this crate should not use getentropy(2). -use crate::Error; +use crate::{Error, util_libc}; use core::{ffi::c_void, mem::MaybeUninit}; pub use crate::util::{inner_u32, inner_u64}; -#[path = "../util_libc.rs"] -mod util_libc; - const MAX_BYTES: usize = 1024; #[inline] diff --git a/src/backends/use_file.rs b/src/backends/use_file.rs index 796dbbc59..c585fb147 100644 --- a/src/backends/use_file.rs +++ b/src/backends/use_file.rs @@ -1,5 +1,5 @@ //! Implementations that just need to read from a file -use crate::Error; +use crate::{Error, util_libc}; use core::{ ffi::{CStr, c_void}, mem::MaybeUninit, @@ -9,9 +9,6 @@ use core::{ #[cfg(not(any(target_os = "android", target_os = "linux")))] pub use crate::util::{inner_u32, inner_u64}; -#[path = "../util_libc.rs"] -pub(super) mod util_libc; - /// For all platforms, we use `/dev/urandom` rather than `/dev/random`. /// For more information see the linked man pages in lib.rs. /// - On Linux, "/dev/urandom is preferred and sufficient in all use cases". diff --git a/src/backends/vxworks.rs b/src/backends/vxworks.rs index 5f5e6773b..663356fb8 100644 --- a/src/backends/vxworks.rs +++ b/src/backends/vxworks.rs @@ -1,14 +1,11 @@ //! Implementation for VxWorks -use crate::Error; +use crate::{Error, util_libc}; use core::{ cmp::Ordering::{Equal, Greater, Less}, mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering::Relaxed}, }; -#[path = "../util_libc.rs"] -mod util_libc; - pub use crate::util::{inner_u32, inner_u64}; static RNG_INIT: AtomicBool = AtomicBool::new(false); diff --git a/src/error.rs b/src/error.rs index 069d8c109..238cd5fce 100644 --- a/src/error.rs +++ b/src/error.rs @@ -59,7 +59,6 @@ impl Error { /// Creates a new instance of an `Error` from a negative error code. #[cfg(not(target_os = "uefi"))] - #[allow(dead_code)] pub(super) fn from_neg_error_code(code: RawOsError) -> Self { if code < 0 { let code = NonZeroRawOsError::new(code).expect("`code` is negative"); @@ -71,7 +70,6 @@ impl Error { /// Creates a new instance of an `Error` from an UEFI error code. #[cfg(target_os = "uefi")] - #[allow(dead_code)] pub(super) fn from_uefi_code(code: RawOsError) -> Self { if code & UEFI_ERROR_FLAG != 0 { let code = NonZeroRawOsError::new(code).expect("The highest bit of `code` is set to 1"); diff --git a/src/lib.rs b/src/lib.rs index ed69ad234..a651ab968 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,8 +33,13 @@ extern crate cfg_if; use core::mem::MaybeUninit; mod backends; +#[allow(dead_code, reason = "not used in all backends")] mod error; +#[allow(dead_code, reason = "not used in all backends")] +mod lazy; +#[allow(dead_code, reason = "not used in all backends")] mod util; +mod util_libc; #[cfg(feature = "std")] mod error_std_impls; diff --git a/src/util.rs b/src/util.rs index ef700e85f..776abc4a9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] use crate::Error; use core::{mem::MaybeUninit, ptr, slice}; diff --git a/src/util_libc.rs b/src/util_libc.rs index 69432891c..af69ca42e 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -1,81 +1,93 @@ -use crate::Error; -use core::mem::MaybeUninit; +#[allow(unused_macros, reason = "not always used")] +macro_rules! emit_impl { + ($get_errno:expr) => { + use crate::Error; + use core::mem::MaybeUninit; -cfg_if! { - if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] { - use libc::__errno as errno_location; - } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] { - use libc::__errno_location as errno_location; - } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { - use libc::___errno as errno_location; - } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] { - use libc::__error as errno_location; - } else if #[cfg(target_os = "haiku")] { - use libc::_errnop as errno_location; - } else if #[cfg(target_os = "nto")] { - use libc::__get_errno_ptr as errno_location; - } else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] { - unsafe extern "C" { - // Not provided by libc: https://github.com/rust-lang/libc/issues/1995 - fn __errno() -> *mut libc::c_int; + pub(crate) fn last_os_error() -> Error { + // We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32` + let errno: i32 = unsafe { $get_errno }; + + if errno > 0 { + let code = errno + .checked_neg() + .expect("Positive number can be always negated"); + Error::from_neg_error_code(code) + } else { + Error::ERRNO_NOT_POSITIVE + } } - use __errno as errno_location; - } else if #[cfg(target_os = "aix")] { - use libc::_Errno as errno_location; - } -} -cfg_if! { - if #[cfg(target_os = "vxworks")] { - use libc::errnoGet as get_errno; - } else { - unsafe fn get_errno() -> libc::c_int { unsafe { *errno_location() }} - } + /// Fill a buffer by repeatedly invoking `sys_fill`. + /// + /// The `sys_fill` function: + /// - should return -1 and set errno on failure + /// - should return the number of bytes written on success + #[allow(dead_code, reason = "not used in all backends")] + pub(crate) fn sys_fill_exact( + mut buf: &mut [MaybeUninit], + sys_fill: impl Fn(&mut [MaybeUninit]) -> libc::ssize_t, + ) -> Result<(), Error> { + while !buf.is_empty() { + let res = sys_fill(buf); + match res { + 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. + if err.raw_os_error() != Some(libc::EINTR) { + return Err(err); + } + } + // Negative return codes not equal to -1 should be impossible. + // EOF (ret = 0) should be impossible, as the data we are reading + // should be an infinite stream of random bytes. + _ => return Err(Error::UNEXPECTED), + } + } + Ok(()) + } + }; } -pub(crate) fn last_os_error() -> Error { - // We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32` - let errno: i32 = unsafe { get_errno() }; - - if errno > 0 { - let code = errno - .checked_neg() - .expect("Positive number can be always negated"); - Error::from_neg_error_code(code) - } else { - Error::ERRNO_NOT_POSITIVE - } +#[allow(unused_macros, reason = "not always used")] +macro_rules! emit_impl_from_ptr { + ($fn:path) => { + emit_impl!(*$fn()); + }; } -/// Fill a buffer by repeatedly invoking `sys_fill`. -/// -/// The `sys_fill` function: -/// - should return -1 and set errno on failure -/// - should return the number of bytes written on success -#[allow(dead_code)] -pub(crate) fn sys_fill_exact( - mut buf: &mut [MaybeUninit], - sys_fill: impl Fn(&mut [MaybeUninit]) -> libc::ssize_t, -) -> Result<(), Error> { - while !buf.is_empty() { - let res = sys_fill(buf); - match res { - 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. - if err.raw_os_error() != Some(libc::EINTR) { - return Err(err); +cfg_if! { + if #[cfg(target_os = "vxworks")] { + emit_impl!(libc::errnoGet()); + } else { + cfg_if! { + if #[cfg(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))] { + // No libc. + } else if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] { + emit_impl_from_ptr!(libc::__errno); + } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] { + emit_impl_from_ptr!(libc::__errno_location); + } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { + emit_impl_from_ptr!(libc::___errno); + } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] { + emit_impl_from_ptr!(libc::__error); + } else if #[cfg(target_os = "haiku")] { + emit_impl_from_ptr!(libc::_errnop); + } else if #[cfg(target_os = "nto")] { + emit_impl_from_ptr!(libc::__get_errno_ptr); + } else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] { + unsafe extern "C" { + // Not provided by libc: https://github.com/rust-lang/libc/issues/1995 + fn __errno() -> *mut libc::c_int; } + emit_impl_from_ptr!(__errno); + } else if #[cfg(target_os = "aix")] { + emit_impl_from_ptr!(libc::_Errno); } - // Negative return codes not equal to -1 should be impossible. - // EOF (ret = 0) should be impossible, as the data we are reading - // should be an infinite stream of random bytes. - _ => return Err(Error::UNEXPECTED), } } - Ok(()) }