|
| 1 | +// Copyright Kani Contributors |
| 2 | +// SPDX-License-Identifier: Apache-2.0 OR MIT |
| 3 | +// |
| 4 | +// Test atomic intrinsics through the stable interface of atomic_ptr. |
| 5 | +// Specifically, it checks that Kani correctly handles atomic_ptr's fetch methods, in which the second argument is a pointer type. |
| 6 | +// These methods were not correctly handled as explained in https://github.com/model-checking/kani/issues/3042. |
| 7 | + |
| 8 | +#![feature(strict_provenance_atomic_ptr, strict_provenance)] |
| 9 | +use std::sync::atomic::{AtomicPtr, Ordering}; |
| 10 | + |
| 11 | +#[kani::proof] |
| 12 | +fn check_fetch_byte_add() { |
| 13 | + let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); |
| 14 | + assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0); |
| 15 | + // Note: in units of bytes, not `size_of::<i64>()`. |
| 16 | + assert_eq!(atom.load(Ordering::Relaxed).addr(), 1); |
| 17 | +} |
| 18 | + |
| 19 | +#[kani::proof] |
| 20 | +fn check_fetch_byte_sub() { |
| 21 | + let atom = AtomicPtr::<i64>::new(core::ptr::invalid_mut(1)); |
| 22 | + assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1); |
| 23 | + assert_eq!(atom.load(Ordering::Relaxed).addr(), 0); |
| 24 | +} |
| 25 | + |
| 26 | +#[kani::proof] |
| 27 | +fn check_fetch_and() { |
| 28 | + let pointer = &mut 3i64 as *mut i64; |
| 29 | + // A tagged pointer |
| 30 | + let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1)); |
| 31 | + assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1); |
| 32 | + // Untag, and extract the previously tagged pointer. |
| 33 | + let untagged = atom.fetch_and(!1, Ordering::Relaxed).map_addr(|a| a & !1); |
| 34 | + assert_eq!(untagged, pointer); |
| 35 | +} |
| 36 | + |
| 37 | +#[kani::proof] |
| 38 | +fn check_fetch_or() { |
| 39 | + let pointer = &mut 3i64 as *mut i64; |
| 40 | + |
| 41 | + let atom = AtomicPtr::<i64>::new(pointer); |
| 42 | + // Tag the bottom bit of the pointer. |
| 43 | + assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0); |
| 44 | + // Extract and untag. |
| 45 | + let tagged = atom.load(Ordering::Relaxed); |
| 46 | + assert_eq!(tagged.addr() & 1, 1); |
| 47 | + assert_eq!(tagged.map_addr(|p| p & !1), pointer); |
| 48 | +} |
| 49 | + |
| 50 | +#[kani::proof] |
| 51 | +fn check_fetch_update() { |
| 52 | + let ptr: *mut _ = &mut 5; |
| 53 | + let some_ptr = AtomicPtr::new(ptr); |
| 54 | + |
| 55 | + let new: *mut _ = &mut 10; |
| 56 | + assert_eq!(some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr)); |
| 57 | + let result = some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| { |
| 58 | + if x == ptr { Some(new) } else { None } |
| 59 | + }); |
| 60 | + assert_eq!(result, Ok(ptr)); |
| 61 | + assert_eq!(some_ptr.load(Ordering::SeqCst), new); |
| 62 | +} |
| 63 | + |
| 64 | +#[kani::proof] |
| 65 | +fn check_fetch_xor() { |
| 66 | + let pointer = &mut 3i64 as *mut i64; |
| 67 | + let atom = AtomicPtr::<i64>::new(pointer); |
| 68 | + |
| 69 | + // Toggle a tag bit on the pointer. |
| 70 | + atom.fetch_xor(1, Ordering::Relaxed); |
| 71 | + assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1); |
| 72 | +} |
0 commit comments