getrandom/backends/
linux_android_with_fallback.rs1use super::use_file;
3use crate::Error;
4use core::{
5 ffi::c_void,
6 mem::{self, MaybeUninit},
7 ptr::{self, NonNull},
8 sync::atomic::{AtomicPtr, Ordering},
9};
10use use_file::util_libc;
11
12pub use crate::util::{inner_u32, inner_u64};
13
14type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;
15
16const NOT_AVAILABLE: NonNull<c_void> = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) };
19
20static GETRANDOM_FN: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
21
22#[cold]
23fn init() -> NonNull<c_void> {
24 static NAME: &[u8] = b"getrandom\0";
25 let name_ptr = NAME.as_ptr().cast::<libc::c_char>();
26 let raw_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) };
27 let res_ptr = match NonNull::new(raw_ptr) {
28 Some(fptr) => {
29 let getrandom_fn = unsafe { mem::transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
30 let dangling_ptr = ptr::NonNull::dangling().as_ptr();
31 let res = unsafe { getrandom_fn(dangling_ptr, 0, 0) };
33 if cfg!(getrandom_test_linux_fallback) {
34 NOT_AVAILABLE
35 } else if res.is_negative() {
36 match util_libc::last_os_error().raw_os_error() {
37 Some(libc::ENOSYS) => NOT_AVAILABLE, #[cfg(target_os = "linux")]
42 Some(libc::EPERM) => NOT_AVAILABLE, _ => fptr,
44 }
45 } else {
46 fptr
47 }
48 }
49 None => NOT_AVAILABLE,
50 };
51
52 GETRANDOM_FN.store(res_ptr.as_ptr(), Ordering::Release);
53 res_ptr
54}
55
56#[inline(never)]
58fn use_file_fallback(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
59 use_file::fill_inner(dest)
60}
61
62pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
63 let raw_ptr = GETRANDOM_FN.load(Ordering::Acquire);
70 let fptr = match NonNull::new(raw_ptr) {
71 Some(p) => p,
72 None => init(),
73 };
74
75 if fptr == NOT_AVAILABLE {
76 use_file_fallback(dest)
77 } else {
78 let getrandom_fn = unsafe { mem::transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
80 util_libc::sys_fill_exact(dest, |buf| unsafe {
81 getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0)
82 })
83 }
84}