铸造任意类型的安全性使用

时间:2015-09-28 12:11:41

标签: casting rust atomic undefined-behavior

我写了一些代码。它有效......但它安全吗?

use std::mem;
use std::ptr;
use std::marker::PhantomData;

struct Atomic<T: Copy>(AtomicUsize, PhantomData<T>);

impl<T: Copy> Atomic<T> {
    unsafe fn encode(src: T) -> usize {
        assert!(mem::size_of::<T>() <= mem::size_of::<usize>());

        let mut dst = 0;
        ptr::write(&mut dst as *mut usize as *mut T, src);
        dst
    }

    unsafe fn decode(src: usize) -> T {
        assert!(mem::size_of::<T>() <= mem::size_of::<usize>());
        ptr::read(&src as *const usize as *const T)
    }

    fn new(val: T) -> Atomic<T> {
        unsafe {
            Atomic(AtomicUsize::new(Self::encode(val)), PhantomData)
        }
    }

    fn load(&self, order: Ordering) -> T {
        unsafe { Self::decode(self.0.load(order)) }
    }

    fn store(&self, val: T, order: Ordering) {
        unsafe { self.0.store(Self::encode(val), order) }
    }
}

impl<T: Copy + Default> Default for Atomic<T> {
    fn default() -> Atomic<T> {
        Self::new(T::default())
    }
}

正如您所看到的,我将一个足够小的Copy值写入usize,然后将其发送到Atomic。然后我把它读作一个新值。

本质上,我使用usize作为大小为size_of::<usize>()的内存块。

如果这是安全的,下一步是考虑更高级的操作。

unsafe trait PackedInt {}
unsafe impl PackedInt for u8  {}
unsafe impl PackedInt for i8  {}
unsafe impl PackedInt for u32 {}
unsafe impl PackedInt for i32 {}
unsafe impl PackedInt for u64 {}
unsafe impl PackedInt for i64 {}

impl<T: Copy + PackedInt> Atomic<T> {
    fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T {
        unsafe {
            Self::decode(self.0.compare_and_swap(
                Self::encode(current),
                Self::encode(new),
                order
            ))
        }
    }

    fn fetch_add(&self, val: T, order: Ordering) -> T {
        unsafe {
            Self::decode(self.0.fetch_add(Self::encode(val), order))
        }
    }

    fn fetch_sub(&self, val: T, order: Ordering) -> T {
        unsafe {
            Self::decode(self.0.fetch_sub(Self::encode(val), order))
        }
    }
}

这些当然在溢出时并不总是特别明显(因为两个“相等”值可能因T之外的位而不相等),但它们看起来仍然很明确......我想。 / p>

那么,这样安全,为什么?

1 个答案:

答案 0 :(得分:2)

这几乎是安全的......但并不完全。您可能只考虑使用带有整数和浮点数的Atomic的人,但引用也是Copy。用户可以轻松地使用Atomic<&&u32>上的轻松加载和存储来导致崩溃。

另一方面,您的fetch_addfetch_sub无法在大端系统上正常运行。