Skip to content

Commit

Permalink
Use real strict_provenance/exposed_provenance APIs on Rust 1.84+ and …
Browse files Browse the repository at this point in the history
…apply fuzzy_provenance_casts lint
  • Loading branch information
taiki-e committed Jan 5, 2025
1 parent 79fee52 commit da703af
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 68 deletions.
30 changes: 16 additions & 14 deletions bench/benches/imp/spinlock_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use core::{
};

use super::fallback::utils::{Backoff, CachePadded};
#[cfg(portable_atomic_no_strict_provenance)]
use crate::utils::ptr::PtrExt;

struct Spinlock {
state: AtomicUsize,
Expand Down Expand Up @@ -106,7 +108,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
self.v.get().read()
}
}
Expand All @@ -118,7 +120,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
self.v.get().write(val)
}
}
Expand All @@ -128,7 +130,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(val);
prev
Expand All @@ -148,7 +150,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
if prev == current {
self.v.get().write(new);
Expand Down Expand Up @@ -176,7 +178,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev.wrapping_add(val));
prev
Expand All @@ -188,7 +190,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev.wrapping_sub(val));
prev
Expand All @@ -200,7 +202,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev & val);
prev
Expand All @@ -212,7 +214,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(!(prev & val));
prev
Expand All @@ -224,7 +226,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev | val);
prev
Expand All @@ -236,7 +238,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev ^ val);
prev
Expand All @@ -248,7 +250,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(core::cmp::max(prev, val));
prev
Expand All @@ -260,7 +262,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(core::cmp::min(prev, val));
prev
Expand All @@ -272,7 +274,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(!prev);
prev
Expand All @@ -288,7 +290,7 @@ macro_rules! atomic_int {
// SAFETY: any data races are prevented by the lock and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
let _guard = lock(self.v.get() as usize);
let _guard = lock(self.v.get().addr());
let prev = self.v.get().read();
self.v.get().write(prev.wrapping_neg());
prev
Expand Down
6 changes: 5 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn main() {
// Custom cfgs set by build script. Not public API.
// grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
println!(
"cargo:rustc-check-cfg=cfg(portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_new_atomic_intrinsics,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_offset_of,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_feature,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
"cargo:rustc-check-cfg=cfg(portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_new_atomic_intrinsics,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_offset_of,portable_atomic_no_strict_provenance,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_feature,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
);
// TODO: handle multi-line target_feature_fallback
// grep -F 'target_feature_fallback("' build.rs | grep -Ev '^ *//' | sed -E 's/^.*target_feature_fallback\(//; s/",.*$/"/' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
Expand Down Expand Up @@ -126,6 +126,10 @@ fn main() {
if !version.probe(83, 2024, 9, 15) {
println!("cargo:rustc-cfg=portable_atomic_no_const_mut_refs");
}
// strict_provenance/exposed_provenance APIs stabilized in Rust 1.84 (nightly-2024-10-22): https://github.com/rust-lang/rust/pull/130350
if !version.probe(84, 2024, 10, 21) {
println!("cargo:rustc-cfg=portable_atomic_no_strict_provenance");
}

// asm! on AArch64, Arm, RISC-V, x86, and x86_64 stabilized in Rust 1.59 (nightly-2021-12-16): https://github.com/rust-lang/rust/pull/91728
let no_asm = !version.probe(59, 2021, 12, 15);
Expand Down
8 changes: 6 additions & 2 deletions portable-atomic-util/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ fn main() {

if version.minor >= 80 {
// Custom cfgs set by build script. Not public API.
// grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
// grep -F 'cargo:rustc-cfg=' portable-atomic-util/build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
println!(
"cargo:rustc-check-cfg=cfg(portable_atomic_no_alloc,portable_atomic_no_alloc_layout_extras,portable_atomic_no_core_unwind_safe,portable_atomic_no_error_in_core,portable_atomic_no_futures_api,portable_atomic_no_io_safety,portable_atomic_no_io_vec,portable_atomic_no_maybe_uninit,portable_atomic_no_min_const_generics,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_sanitize_thread)"
"cargo:rustc-check-cfg=cfg(portable_atomic_no_alloc,portable_atomic_no_alloc_layout_extras,portable_atomic_no_core_unwind_safe,portable_atomic_no_error_in_core,portable_atomic_no_futures_api,portable_atomic_no_io_safety,portable_atomic_no_io_vec,portable_atomic_no_maybe_uninit,portable_atomic_no_min_const_generics,portable_atomic_no_strict_provenance,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_sanitize_thread)"
);
}

Expand Down Expand Up @@ -85,6 +85,10 @@ fn main() {
if !version.probe(81, 2024, 6, 8) {
println!("cargo:rustc-cfg=portable_atomic_no_error_in_core");
}
// strict_provenance/exposed_provenance APIs stabilized in Rust 1.84 (nightly-2024-10-22): https://github.com/rust-lang/rust/pull/130350
if !version.probe(84, 2024, 10, 21) {
println!("cargo:rustc-cfg=portable_atomic_no_strict_provenance");
}

if version.nightly {
// `cfg(sanitize = "..")` is not stabilized.
Expand Down
38 changes: 35 additions & 3 deletions portable-atomic-util/src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3020,7 +3020,7 @@ fn abort() -> ! {
}

fn is_dangling<T: ?Sized>(ptr: *const T) -> bool {
ptr as *const () as usize == usize::MAX
(ptr as *const ()).addr() == usize::MAX
}

// Based on unstable alloc::alloc::Global.
Expand Down Expand Up @@ -3061,8 +3061,18 @@ impl Global {
}
}

// TODO: use stabilized core::ptr strict_provenance helpers https://github.com/rust-lang/rust/pull/130350
#[cfg(portable_atomic_no_strict_provenance)]
use self::strict::PtrExt;

// strict_provenance polyfill for pre-1.84 rustc.
mod strict {
#[cfg(portable_atomic_no_strict_provenance)]
use core::mem;
#[cfg(not(portable_atomic_no_strict_provenance))]
#[allow(unused_imports)]
pub(crate) use core::ptr::without_provenance_mut;

#[cfg(portable_atomic_no_strict_provenance)]
#[inline(always)]
#[must_use]
pub(super) const fn without_provenance_mut<T>(addr: usize) -> *mut T {
Expand All @@ -3073,7 +3083,7 @@ mod strict {
// pointer).
#[cfg(miri)]
unsafe {
core::mem::transmute(addr)
mem::transmute(addr)
}
// const transmute requires Rust 1.56.
#[cfg(not(miri))]
Expand Down Expand Up @@ -3111,4 +3121,26 @@ mod strict {
// SAFETY: the caller must uphold the safety contract for `sub`.
unsafe { with_metadata_of((ptr as *mut u8).sub(count), ptr) }
}

#[cfg(portable_atomic_no_strict_provenance)]
pub(crate) trait PtrExt<T: ?Sized>: Copy {
#[must_use]
fn addr(self) -> usize;
}
#[cfg(portable_atomic_no_strict_provenance)]
impl<T: ?Sized> PtrExt<T> for *const T {
#[must_use]
#[inline(always)]
fn addr(self) -> usize {
// A pointer-to-integer transmute currently has exactly the right semantics: it returns the
// address without exposing the provenance. Note that this is *not* a stable guarantee about
// transmute semantics, it relies on sysroot crates having special status.
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
// provenance).
#[allow(clippy::transmutes_expressible_as_ptr_casts)]
unsafe {
mem::transmute(self as *const ())
}
}
}
}
1 change: 1 addition & 0 deletions portable-atomic-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ RUSTFLAGS="--cfg portable_atomic_unstable_coerce_unsized" cargo ...
clippy::std_instead_of_alloc,
clippy::std_instead_of_core,
)]
#![cfg_attr(portable_atomic_no_strict_provenance, allow(unstable_name_collisions))]
#![allow(clippy::inline_always)]
// docs.rs only (cfg is enabled by docs.rs, not build script)
#![cfg_attr(docsrs, feature(doc_cfg))]
Expand Down
4 changes: 2 additions & 2 deletions src/imp/atomic64/arm_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn __kuser_helper_version() -> i32 {
// SAFETY: core assumes that at least __kuser_memory_barrier (__kuser_helper_version >= 3,
// kernel version 2.6.15+) is available on this platform. __kuser_helper_version
// is always available on such a platform.
v = unsafe { (KUSER_HELPER_VERSION as *const i32).read() };
v = unsafe { crate::utils::ptr::with_exposed_provenance::<i32>(KUSER_HELPER_VERSION).read() };
CACHE.store(v, Ordering::Relaxed);
v
}
Expand All @@ -61,7 +61,7 @@ unsafe fn __kuser_cmpxchg64(old_val: *const u64, new_val: *const u64, ptr: *mut
// SAFETY: the caller must uphold the safety contract.
unsafe {
let f: extern "C" fn(*const u64, *const u64, *mut u64) -> u32 =
mem::transmute(KUSER_CMPXCHG64 as *const ());
mem::transmute(crate::utils::ptr::with_exposed_provenance::<()>(KUSER_CMPXCHG64));
f(old_val, new_val, ptr) == 0
}
}
Expand Down
Loading

0 comments on commit da703af

Please sign in to comment.