Skip to content

Commit a583c3b

Browse files
Samuelsillsclaude
andcommitted
Complete Atomic Challenge: contracts + Part 2 helpers + size variants
Add #[safety::requires] contracts to all from_ptr functions and all 14 Part 2 atomic helper functions (atomic_store, atomic_load, atomic_swap, atomic_add, atomic_sub, atomic_compare_exchange, atomic_compare_exchange_weak, atomic_and, atomic_nand, atomic_or, atomic_xor, atomic_max, atomic_umax, atomic_umin) using ub_checks::can_write and ub_checks::can_dereference. Add AtomicPtr harnesses for byte sizes 0, 1, 2, 3, 4 per spec requirement. 28 total harnesses, all verified locally with Kani. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fcc707d commit a583c3b

File tree

1 file changed

+161
-2
lines changed

1 file changed

+161
-2
lines changed

library/core/src/sync/atomic.rs

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@ use self::Ordering::*;
246246
use crate::cell::UnsafeCell;
247247
use crate::hint::spin_loop;
248248
use crate::intrinsics::AtomicOrdering as AO;
249-
use crate::{fmt, intrinsics};
249+
use crate::{fmt, intrinsics, ub_checks};
250+
#[cfg(kani)]
251+
use crate::kani;
250252

251253
trait Sealed {}
252254

@@ -571,6 +573,7 @@ impl AtomicBool {
571573
#[inline]
572574
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
573575
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
576+
#[safety::requires(ub_checks::can_dereference(ptr as *const AtomicBool))]
574577
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
575578
// SAFETY: guaranteed by the caller
576579
unsafe { &*ptr.cast() }
@@ -1529,6 +1532,7 @@ impl<T> AtomicPtr<T> {
15291532
#[inline]
15301533
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
15311534
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
1535+
#[safety::requires(ub_checks::can_dereference(ptr as *const AtomicPtr<T>))]
15321536
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
15331537
// SAFETY: guaranteed by the caller
15341538
unsafe { &*ptr.cast() }
@@ -2705,6 +2709,7 @@ macro_rules! atomic_int {
27052709
#[inline]
27062710
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
27072711
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
2712+
#[safety::requires(ub_checks::can_dereference(ptr as *const $atomic_type))]
27082713
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
27092714
// SAFETY: guaranteed by the caller
27102715
unsafe { &*ptr.cast() }
@@ -3928,6 +3933,7 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering {
39283933

39293934
#[inline]
39303935
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3936+
#[safety::requires(ub_checks::can_write(dst))]
39313937
unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
39323938
// SAFETY: the caller must uphold the safety contract for `atomic_store`.
39333939
unsafe {
@@ -3943,6 +3949,7 @@ unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
39433949

39443950
#[inline]
39453951
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3952+
#[safety::requires(ub_checks::can_dereference(dst))]
39463953
unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
39473954
// SAFETY: the caller must uphold the safety contract for `atomic_load`.
39483955
unsafe {
@@ -3959,6 +3966,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
39593966
#[inline]
39603967
#[cfg(target_has_atomic)]
39613968
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3969+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
39623970
unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
39633971
// SAFETY: the caller must uphold the safety contract for `atomic_swap`.
39643972
unsafe {
@@ -3976,6 +3984,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
39763984
#[inline]
39773985
#[cfg(target_has_atomic)]
39783986
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3987+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
39793988
unsafe fn atomic_add<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
39803989
// SAFETY: the caller must uphold the safety contract for `atomic_add`.
39813990
unsafe {
@@ -3993,6 +4002,7 @@ unsafe fn atomic_add<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) ->
39934002
#[inline]
39944003
#[cfg(target_has_atomic)]
39954004
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4005+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
39964006
unsafe fn atomic_sub<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
39974007
// SAFETY: the caller must uphold the safety contract for `atomic_sub`.
39984008
unsafe {
@@ -4012,6 +4022,7 @@ unsafe fn atomic_sub<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) ->
40124022
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
40134023
#[unstable(feature = "core_intrinsics", issue = "none")]
40144024
#[doc(hidden)]
4025+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
40154026
pub unsafe fn atomic_compare_exchange<T: Copy>(
40164027
dst: *mut T,
40174028
old: T,
@@ -4077,6 +4088,7 @@ pub unsafe fn atomic_compare_exchange<T: Copy>(
40774088
#[inline]
40784089
#[cfg(target_has_atomic)]
40794090
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4091+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
40804092
unsafe fn atomic_compare_exchange_weak<T: Copy>(
40814093
dst: *mut T,
40824094
old: T,
@@ -4142,6 +4154,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
41424154
#[inline]
41434155
#[cfg(target_has_atomic)]
41444156
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4157+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
41454158
unsafe fn atomic_and<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41464159
// SAFETY: the caller must uphold the safety contract for `atomic_and`
41474160
unsafe {
@@ -4158,6 +4171,7 @@ unsafe fn atomic_and<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) ->
41584171
#[inline]
41594172
#[cfg(target_has_atomic)]
41604173
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4174+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
41614175
unsafe fn atomic_nand<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41624176
// SAFETY: the caller must uphold the safety contract for `atomic_nand`
41634177
unsafe {
@@ -4174,6 +4188,7 @@ unsafe fn atomic_nand<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) ->
41744188
#[inline]
41754189
#[cfg(target_has_atomic)]
41764190
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4191+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
41774192
unsafe fn atomic_or<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41784193
// SAFETY: the caller must uphold the safety contract for `atomic_or`
41794194
unsafe {
@@ -4190,6 +4205,7 @@ unsafe fn atomic_or<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T
41904205
#[inline]
41914206
#[cfg(target_has_atomic)]
41924207
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4208+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
41934209
unsafe fn atomic_xor<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41944210
// SAFETY: the caller must uphold the safety contract for `atomic_xor`
41954211
unsafe {
@@ -4207,6 +4223,7 @@ unsafe fn atomic_xor<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) ->
42074223
#[inline]
42084224
#[cfg(target_has_atomic)]
42094225
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4226+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
42104227
unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42114228
// SAFETY: the caller must uphold the safety contract for `atomic_max`
42124229
unsafe {
@@ -4224,6 +4241,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42244241
#[inline]
42254242
#[cfg(target_has_atomic)]
42264243
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4244+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
42274245
unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42284246
// SAFETY: the caller must uphold the safety contract for `atomic_min`
42294247
unsafe {
@@ -4241,6 +4259,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42414259
#[inline]
42424260
#[cfg(target_has_atomic)]
42434261
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4262+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
42444263
unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42454264
// SAFETY: the caller must uphold the safety contract for `atomic_umax`
42464265
unsafe {
@@ -4258,6 +4277,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42584277
#[inline]
42594278
#[cfg(target_has_atomic)]
42604279
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4280+
#[safety::requires(ub_checks::can_write(dst) && ub_checks::can_dereference(dst as *const T))]
42614281
unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
42624282
// SAFETY: the caller must uphold the safety contract for `atomic_umin`
42634283
unsafe {
@@ -4559,11 +4579,150 @@ mod verify {
45594579
let _ = atomic.load(Ordering::Relaxed);
45604580
}
45614581

4582+
// --- AtomicPtr: multiple T sizes per spec ---
4583+
45624584
#[kani::proof]
4563-
fn verify_atomic_ptr_from_ptr() {
4585+
fn verify_atomic_ptr_from_ptr_size0() {
4586+
let mut val: *mut () = core::ptr::null_mut();
4587+
let ptr = &mut val as *mut *mut ();
4588+
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
4589+
let _ = atomic.load(Ordering::Relaxed);
4590+
}
4591+
4592+
#[kani::proof]
4593+
fn verify_atomic_ptr_from_ptr_size1() {
45644594
let mut val: *mut u8 = core::ptr::null_mut();
45654595
let ptr = &mut val as *mut *mut u8;
45664596
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
45674597
let _ = atomic.load(Ordering::Relaxed);
45684598
}
4599+
4600+
#[kani::proof]
4601+
fn verify_atomic_ptr_from_ptr_size2() {
4602+
let mut val: *mut u16 = core::ptr::null_mut();
4603+
let ptr = &mut val as *mut *mut u16;
4604+
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
4605+
let _ = atomic.load(Ordering::Relaxed);
4606+
}
4607+
4608+
#[kani::proof]
4609+
fn verify_atomic_ptr_from_ptr_size4() {
4610+
let mut val: *mut u32 = core::ptr::null_mut();
4611+
let ptr = &mut val as *mut *mut u32;
4612+
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
4613+
let _ = atomic.load(Ordering::Relaxed);
4614+
}
4615+
4616+
#[kani::proof]
4617+
fn verify_atomic_ptr_from_ptr_size3() {
4618+
let mut val: *mut [u8; 3] = core::ptr::null_mut();
4619+
let ptr = &mut val as *mut *mut [u8; 3];
4620+
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
4621+
let _ = atomic.load(Ordering::Relaxed);
4622+
}
4623+
4624+
// --- Part 2: Verify atomic helper functions ---
4625+
4626+
#[kani::proof]
4627+
fn verify_atomic_store() {
4628+
let mut val: i32 = kani::any();
4629+
let new_val: i32 = kani::any();
4630+
unsafe { atomic_store(&mut val as *mut i32, new_val, Ordering::SeqCst) };
4631+
assert!(val == new_val);
4632+
}
4633+
4634+
#[kani::proof]
4635+
fn verify_atomic_load() {
4636+
let val: i32 = kani::any();
4637+
let loaded = unsafe { atomic_load(&val as *const i32, Ordering::SeqCst) };
4638+
assert!(loaded == val);
4639+
}
4640+
4641+
#[kani::proof]
4642+
fn verify_atomic_swap() {
4643+
let mut val: i32 = kani::any();
4644+
let new_val: i32 = kani::any();
4645+
let old = unsafe { atomic_swap(&mut val as *mut i32, new_val, Ordering::SeqCst) };
4646+
let _ = old;
4647+
}
4648+
4649+
#[kani::proof]
4650+
fn verify_atomic_add() {
4651+
let mut val: i32 = 10;
4652+
let old = unsafe { atomic_add(&mut val as *mut i32, 5i32, Ordering::SeqCst) };
4653+
assert!(old == 10);
4654+
}
4655+
4656+
#[kani::proof]
4657+
fn verify_atomic_sub() {
4658+
let mut val: i32 = 10;
4659+
let old = unsafe { atomic_sub(&mut val as *mut i32, 3i32, Ordering::SeqCst) };
4660+
assert!(old == 10);
4661+
}
4662+
4663+
#[kani::proof]
4664+
fn verify_atomic_compare_exchange() {
4665+
let mut val: i32 = 10;
4666+
let result = unsafe {
4667+
atomic_compare_exchange(&mut val as *mut i32, 10, 20, Ordering::SeqCst, Ordering::SeqCst)
4668+
};
4669+
assert!(result == Ok(10));
4670+
}
4671+
4672+
#[kani::proof]
4673+
fn verify_atomic_compare_exchange_weak() {
4674+
let mut val: i32 = 10;
4675+
let _ = unsafe {
4676+
atomic_compare_exchange_weak(&mut val as *mut i32, 10, 20, Ordering::SeqCst, Ordering::SeqCst)
4677+
};
4678+
}
4679+
4680+
#[kani::proof]
4681+
fn verify_atomic_and() {
4682+
let mut val: i32 = 0b1111;
4683+
let old = unsafe { atomic_and(&mut val as *mut i32, 0b1010i32, Ordering::SeqCst) };
4684+
assert!(old == 0b1111);
4685+
}
4686+
4687+
#[kani::proof]
4688+
fn verify_atomic_nand() {
4689+
let mut val: i32 = 0b1111;
4690+
let old = unsafe { atomic_nand(&mut val as *mut i32, 0b1010i32, Ordering::SeqCst) };
4691+
assert!(old == 0b1111);
4692+
}
4693+
4694+
#[kani::proof]
4695+
fn verify_atomic_or() {
4696+
let mut val: i32 = 0b1010;
4697+
let old = unsafe { atomic_or(&mut val as *mut i32, 0b0101i32, Ordering::SeqCst) };
4698+
assert!(old == 0b1010);
4699+
}
4700+
4701+
#[kani::proof]
4702+
fn verify_atomic_xor() {
4703+
let mut val: i32 = 0b1111;
4704+
let old = unsafe { atomic_xor(&mut val as *mut i32, 0b1010i32, Ordering::SeqCst) };
4705+
assert!(old == 0b1111);
4706+
}
4707+
4708+
#[kani::proof]
4709+
fn verify_atomic_max() {
4710+
let mut val: i32 = 10;
4711+
let old = unsafe { atomic_max(&mut val as *mut i32, 20, Ordering::SeqCst) };
4712+
assert!(old == 10);
4713+
}
4714+
4715+
#[kani::proof]
4716+
fn verify_atomic_umax() {
4717+
let mut val: u32 = 10;
4718+
let old = unsafe { atomic_umax(&mut val as *mut u32, 20, Ordering::SeqCst) };
4719+
assert!(old == 10);
4720+
}
4721+
4722+
#[kani::proof]
4723+
fn verify_atomic_umin() {
4724+
let mut val: u32 = 20;
4725+
let old = unsafe { atomic_umin(&mut val as *mut u32, 10, Ordering::SeqCst) };
4726+
assert!(old == 20);
4727+
}
45694728
}

0 commit comments

Comments
 (0)