Skip to content

Commit 6533252

Browse files
committed
linux_android: Use direct syscall instead of libc to support *-none.
Remove the last libc dependency from `linux_android`, as a step towards supporting x86_64-unknown-linux-none. This requires bumping the MSRV to 1.59.
1 parent 74c43c2 commit 6533252

8 files changed

+89
-21
lines changed

.clippy.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
msrv = "1.57"
1+
msrv = "1.59"

.github/workflows/tests.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
strategy:
4545
matrix:
4646
os: [ubuntu-22.04, windows-2022]
47-
toolchain: [nightly, beta, stable, 1.57]
47+
toolchain: [nightly, beta, stable, 1.59]
4848
# Only Test macOS on stable to reduce macOS CI jobs
4949
include:
5050
# x86_64-apple-darwin.
@@ -61,6 +61,8 @@ jobs:
6161
- uses: Swatinem/rust-cache@v2
6262
- run: cargo test
6363
- run: cargo test --features=std
64+
# This is assumed to be the same code path as x86_64-*-linux-none, since
65+
# we don't/can't run tests for that target yet.
6466
- run: cargo test --features=linux_disable_fallback
6567
- run: cargo test --features=custom # custom should do nothing here
6668
- if: ${{ matrix.toolchain == 'nightly' }}
@@ -361,6 +363,8 @@ jobs:
361363
features: ["rdrand"]
362364
- target: i686-unknown-hurd-gnu
363365
features: ["std"]
366+
- target: x86_64-unknown-linux-none
367+
features: ["rdrand"]
364368
steps:
365369
- uses: actions/checkout@v3
366370
- uses: dtolnay/rust-toolchain@nightly # Required to build libcore

Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "getrandom"
33
version = "0.2.15" # Also update html_root_url in lib.rs when bumping this
44
edition = "2021"
5-
rust-version = "1.57" # Sync .clippy.toml, tests.yml, and README.md.
5+
rust-version = "1.59" # Sync .clippy.toml, tests.yml, and README.md.
66
authors = ["The Rand Project Developers"]
77
license = "MIT OR Apache-2.0"
88
description = "A small cross-platform library for retrieving random data from system source"
@@ -18,7 +18,11 @@ cfg-if = "1"
1818
compiler_builtins = { version = "0.1", optional = true }
1919
core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }
2020

21-
[target.'cfg(unix)'.dependencies]
21+
# XXX: Additionally, we don't use libc when feature `linux_disable_fallback` is
22+
# enabled on `x86_64-{*-linux-*,linux-android}`, but we can't express this. In
23+
# that case, we require libc to be built, and we force it to be linked, but we
24+
# don't actually use anything from it.
25+
[target.'cfg(all(unix, not(all(target_arch = "x86_64", target_os = "linux", target_env = ""))))'.dependencies]
2226
libc = { version = "0.2.154", default-features = false }
2327

2428
[target.'cfg(target_os = "wasi")'.dependencies]

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the
5252

5353
## Minimum Supported Rust Version
5454

55-
This crate requires Rust 1.57.0 or later.
55+
This crate requires Rust 1.59.0 or later.
5656

5757
## Platform Support
5858

src/lib.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,12 @@ cfg_if! {
259259
mod util_libc;
260260
#[path = "getrandom.rs"] mod imp;
261261
} else if #[cfg(all(
262-
not(feature = "linux_disable_fallback"),
262+
// Always treat feature="linux_disable_fallback" identically to
263+
// all(target_os = "linux", target_env="") to ensure the code paths are
264+
// the same. This is important because we can't run tests for
265+
// *-*-linux-none (yet). Note that target_env="" for common Android
266+
// targets.
267+
not(any(feature = "linux_disable_fallback", all(target_os = "linux", target_env=""))),
263268
any(
264269
// Rust supports Android API level 19 (KitKat) [0] and the next upgrade targets
265270
// level 21 (Lollipop) [1], while `getrandom(2)` was added only in
@@ -304,8 +309,8 @@ cfg_if! {
304309
mod linux_android;
305310
#[path = "linux_android_with_fallback.rs"] mod imp;
306311
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
307-
mod util_libc;
308-
#[path = "linux_android.rs"] mod imp;
312+
mod linux_android;
313+
use linux_android as imp;
309314
} else if #[cfg(target_os = "solaris")] {
310315
mod util_libc;
311316
#[path = "solaris.rs"] mod imp;

src/linux_android.rs

+57-12
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,63 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
66
sys_fill_exact(dest, getrandom_syscall)
77
}
88

9+
// The value of `EINTR` is not architecture-specific. It is checked against
10+
// `libc::EINTR` by linux_android_with_fallback.rs.
11+
pub const EINTR: i32 = 4;
12+
913
// Also used by linux_android_with_fallback to check if the syscall is available.
10-
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
11-
use crate::util_libc::last_os_error;
14+
cfg_if! {
15+
// TODO: Expand inilne assembly to other architectures to avoid depending
16+
// on libc on Linux.
17+
if #[cfg(target_arch = "x86_64")] {
18+
type Word = u64;
19+
type IWord = i64;
20+
21+
#[allow(non_upper_case_globals)]
22+
pub const SYS_getrandom: IWord = if cfg!(target_arch = "x86_64") { 318 } else { unimplemented!() };
23+
24+
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
25+
const _:() = assert!(core::mem::size_of::<Word>() == core::mem::size_of::<usize>());
26+
27+
let mut ret: IWord;
28+
let flags = 0;
29+
unsafe {
30+
core::arch::asm!(
31+
"syscall",
32+
inout("rax") SYS_getrandom => ret,
33+
in("rdi") buf.as_mut_ptr(),
34+
in("rsi") buf.len(),
35+
in("rdx") flags,
36+
lateout("rcx") _,
37+
lateout("r11") _,
38+
options(nostack),
39+
);
40+
}
41+
match Word::try_from(ret) {
42+
Ok(written) => {
43+
const _:() = assert!(core::mem::size_of::<Word>() <= core::mem::size_of::<usize>());
44+
Ok(written as usize)
45+
},
46+
Err(_) => {
47+
Err(u32::try_from(ret.unsigned_abs()).map_or(
48+
Error::UNEXPECTED, Error::from_os_error))
49+
}
50+
}
51+
}
52+
} else {
53+
use crate::util_libc::last_os_error;
1254

13-
let ret: libc::c_long = unsafe {
14-
libc::syscall(
15-
libc::SYS_getrandom,
16-
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
17-
buf.len(),
18-
0,
19-
)
20-
};
21-
const _: () = assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<isize>());
22-
usize::try_from(ret as isize).map_err(|_| last_os_error())
55+
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
56+
let ret: libc::c_long = unsafe {
57+
libc::syscall(
58+
libc::SYS_getrandom,
59+
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
60+
buf.len(),
61+
0,
62+
)
63+
};
64+
const _:() = assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<isize>());
65+
usize::try_from(ret as isize).map_err(|_| last_os_error())
66+
}
67+
}
2368
}

src/linux_android_with_fallback.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
use crate::{lazy::LazyBool, linux_android, use_file, Error};
33
use core::mem::MaybeUninit;
44

5+
const _: () = assert!(linux_android::EINTR == libc::EINTR);
6+
#[cfg(target_arch = "x86_64")]
7+
const _: () = assert!(linux_android::SYS_getrandom == libc::SYS_getrandom);
8+
59
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
610
// getrandom(2) was introduced in Linux 3.17
711
static HAS_GETRANDOM: LazyBool = LazyBool::new();

src/util_unix.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ pub fn sys_fill_exact(
99
mut buf: &mut [MaybeUninit<u8>],
1010
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> Result<usize, Error>,
1111
) -> Result<(), Error> {
12+
// Avoid depending on libc for Linux/Android.
13+
#[cfg(any(target_os = "android", target_os = "linux"))]
14+
use crate::linux_android::EINTR;
15+
#[cfg(not(any(target_os = "android", target_os = "linux")))]
16+
use libc::EINTR;
17+
1218
while !buf.is_empty() {
1319
match sys_fill(buf) {
1420
Ok(res) if res > 0 => buf = buf.get_mut(res..).ok_or(Error::UNEXPECTED)?,
1521
Err(err) => {
1622
// We should try again if the call was interrupted.
17-
if err.raw_os_error() != Some(libc::EINTR) {
23+
if err.raw_os_error() != Some(EINTR) {
1824
return Err(err);
1925
}
2026
}

0 commit comments

Comments
 (0)