From 6f1a72fb37cd5abe663dd252ca171cbe07f41b94 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 18 Mar 2025 22:15:08 +0900 Subject: [PATCH 1/2] std_detect: Always avoid dlsym on *-linux-{musl,ohos}* targets --- ci/build-std-detect.sh | 6 ++++ crates/std_detect/README.md | 9 ++++-- .../std_detect/src/detect/os/linux/auxvec.rs | 30 ++++++++++++++----- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/ci/build-std-detect.sh b/ci/build-std-detect.sh index e4560b3371..e79a497cc3 100755 --- a/ci/build-std-detect.sh +++ b/ci/build-std-detect.sh @@ -10,6 +10,12 @@ set -ex cd "$(dirname "$0")"/.. targets=( + # Linux + aarch64-unknown-linux-musl + armv5te-unknown-linux-musleabi + aarch64-unknown-linux-ohos + armv7-unknown-linux-ohos + # Android aarch64-linux-android arm-linux-androideabi diff --git a/crates/std_detect/README.md b/crates/std_detect/README.md index b9146d42c9..5191b2f665 100644 --- a/crates/std_detect/README.md +++ b/crates/std_detect/README.md @@ -30,12 +30,15 @@ run-time feature detection. When this feature is disabled, `std_detect` assumes that [`getauxval`] is linked to the binary. If that is not the case the behavior is undefined. - Note: This feature is ignored on `*-linux-gnu*` and `*-android*` targets + Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` is linked to the binary. * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) - have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). + have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). + * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) + use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) + * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) - have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). + have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). * `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature detection using file APIs (e.g. `/proc/cpuinfo`, etc.) if other more performant diff --git a/crates/std_detect/src/detect/os/linux/auxvec.rs b/crates/std_detect/src/detect/os/linux/auxvec.rs index 79720a0dee..e8c2dfdc4c 100644 --- a/crates/std_detect/src/detect/os/linux/auxvec.rs +++ b/crates/std_detect/src/detect/os/linux/auxvec.rs @@ -58,10 +58,13 @@ pub(crate) struct AuxVec { /// feature detection on some platforms. /// /// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on -/// `*-linux-gnu*` and `*-android*` targets because we can safely assume `getauxval` +/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` /// is linked to the binary. /// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) /// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). +/// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) +/// use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) +/// - `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) /// - `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) /// have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). /// @@ -73,7 +76,10 @@ pub(crate) struct AuxVec { pub(crate) fn auxv() -> Result { #[cfg(all( feature = "std_detect_dlsym_getauxval", - not(all(target_os = "linux", target_env = "gnu")), + not(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + )), // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. not(all(target_os = "android", target_pointer_width = "64")), ))] @@ -120,12 +126,15 @@ pub(crate) fn auxv() -> Result { } } - #[cfg(any( - not(feature = "std_detect_dlsym_getauxval"), - all(target_os = "linux", target_env = "gnu"), + #[cfg(not(all( + feature = "std_detect_dlsym_getauxval", + not(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + )), // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. - all(target_os = "android", target_pointer_width = "64"), - ))] + not(all(target_os = "android", target_pointer_width = "64")), + )))] { // Targets with only AT_HWCAP: #[cfg(any( @@ -184,7 +193,12 @@ pub(crate) fn auxv() -> Result { test, all( feature = "std_detect_dlsym_getauxval", - not(all(target_os = "linux", target_env = "gnu")) + not(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + )), + // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. + not(all(target_os = "android", target_pointer_width = "64")), ) ))] fn getauxval(key: usize) -> Result { From 2960b074140080208da46870a96ead4b7d03ae35 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 26 Mar 2025 00:49:20 +0900 Subject: [PATCH 2/2] std_detect: Move cfgs into getauxval helper function --- .../std_detect/src/detect/os/linux/auxvec.rs | 129 +++++------------- 1 file changed, 35 insertions(+), 94 deletions(-) diff --git a/crates/std_detect/src/detect/os/linux/auxvec.rs b/crates/std_detect/src/detect/os/linux/auxvec.rs index e8c2dfdc4c..e6a9cae18d 100644 --- a/crates/std_detect/src/detect/os/linux/auxvec.rs +++ b/crates/std_detect/src/detect/os/linux/auxvec.rs @@ -74,68 +74,8 @@ pub(crate) struct AuxVec { /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ pub(crate) fn auxv() -> Result { - #[cfg(all( - feature = "std_detect_dlsym_getauxval", - not(all( - target_os = "linux", - any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. - not(all(target_os = "android", target_pointer_width = "64")), - ))] - { - // Try to call a dynamically-linked getauxval function. - if let Ok(hwcap) = getauxval(AT_HWCAP) { - // Targets with only AT_HWCAP: - #[cfg(any( - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "mips", - target_arch = "mips64" - ))] - { - // Zero could indicate that no features were detected, but it's also used to - // indicate an error. In either case, try the fallback. - if hwcap != 0 { - return Ok(AuxVec { hwcap }); - } - } - - // Targets with AT_HWCAP and AT_HWCAP2: - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - { - if let Ok(hwcap2) = getauxval(AT_HWCAP2) { - // Zero could indicate that no features were detected, but it's also used to - // indicate an error. In particular, on many platforms AT_HWCAP2 will be - // legitimately zero, since it contains the most recent feature flags. Use the - // fallback only if no features were detected at all. - if hwcap != 0 || hwcap2 != 0 { - return Ok(AuxVec { hwcap, hwcap2 }); - } - } - } - - // Intentionnaly not used - let _ = hwcap; - } - } - - #[cfg(not(all( - feature = "std_detect_dlsym_getauxval", - not(all( - target_os = "linux", - any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. - not(all(target_os = "android", target_pointer_width = "64")), - )))] - { + // Try to call a getauxval function. + if let Ok(hwcap) = getauxval(AT_HWCAP) { // Targets with only AT_HWCAP: #[cfg(any( target_arch = "riscv32", @@ -145,7 +85,6 @@ pub(crate) fn auxv() -> Result { target_arch = "loongarch64", ))] { - let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize }; // Zero could indicate that no features were detected, but it's also used to indicate // an error. In either case, try the fallback. if hwcap != 0 { @@ -162,16 +101,19 @@ pub(crate) fn auxv() -> Result { target_arch = "s390x", ))] { - let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize }; - let hwcap2 = unsafe { libc::getauxval(AT_HWCAP2 as libc::c_ulong) as usize }; - // Zero could indicate that no features were detected, but it's also used to indicate - // an error. In particular, on many platforms AT_HWCAP2 will be legitimately zero, - // since it contains the most recent feature flags. Use the fallback only if no - // features were detected at all. - if hwcap != 0 || hwcap2 != 0 { - return Ok(AuxVec { hwcap, hwcap2 }); + if let Ok(hwcap2) = getauxval(AT_HWCAP2) { + // Zero could indicate that no features were detected, but it's also used to indicate + // an error. In particular, on many platforms AT_HWCAP2 will be legitimately zero, + // since it contains the most recent feature flags. Use the fallback only if no + // features were detected at all. + if hwcap != 0 || hwcap2 != 0 { + return Ok(AuxVec { hwcap, hwcap2 }); + } } } + + // Intentionnaly not used + let _ = hwcap; } #[cfg(feature = "std_detect_file_io")] @@ -187,32 +129,31 @@ pub(crate) fn auxv() -> Result { } /// Tries to read the `key` from the auxiliary vector by calling the -/// dynamically-linked `getauxval` function. If the function is not linked, -/// this function return `Err`. -#[cfg(any( - test, - all( - feature = "std_detect_dlsym_getauxval", - not(all( - target_os = "linux", - any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. - not(all(target_os = "android", target_pointer_width = "64")), - ) -))] +/// `getauxval` function. If the function is not linked, this function return `Err`. fn getauxval(key: usize) -> Result { - use libc; - pub type F = unsafe extern "C" fn(usize) -> usize; - unsafe { - let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); - if ptr.is_null() { - return Err(()); + type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; + cfg_if::cfg_if! { + if #[cfg(all( + feature = "std_detect_dlsym_getauxval", + not(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + )), + // TODO: libc crate currently doesn't provide getauxval on 32-bit Android. + not(all(target_os = "android", target_pointer_width = "64")), + ))] { + let ffi_getauxval: F = unsafe { + let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); + if ptr.is_null() { + return Err(()); + } + core::mem::transmute(ptr) + }; + } else { + let ffi_getauxval: F = libc::getauxval; } - - let ffi_getauxval: F = core::mem::transmute(ptr); - Ok(ffi_getauxval(key)) } + Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) } /// Tries to read the auxiliary vector from the `file`. If this fails, this