Ich schrieb etwas Code. Es funktioniert ... aber ist es sicher?Sicherheit des Gießens beliebiger Typen zu verwenden
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())
}
}
Wie man sehen kann, schreibe ich einen beliebigen Copy
Wert klein genug, um eine Größe in ein usize
, und es um in einem Atomic
versenden. Ich lese es dann als neuen Wert vor.
Im Wesentlichen verwende ich die usize
als Speicherblock der Größe size_of::<usize>()
.
Wenn dies sicher ist, ist der nächste Schritt, einen schickeren Betrieb in Betracht zu ziehen.
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))
}
}
}
Diese Überlauf natürlich nicht immer besonders sinnvoll sind (da zwei „gleich“ Werte aufgrund von Bits außerhalb des T
ungleich vergleichen konnte), aber sie scheinen immer noch gut definierte ... denke ich.
Also, ist das sicher und warum?
Beziehen Sie sich auf die [Rust Definition von Sicherheit] (http://doc.rust-lang.org/reference.html#behavior-not-considered-unsafe) (auch relevant, das [undefinierte Verhalten] (http : //doc.rust-lang.org/reference.html#behavior-consided-undefined))? Oder meinst du eine allgemeinere Art von "sicher"? – Shepmaster
Die Rust-Definition, meistens. Kommentare zu besonders überraschenden aber technisch sicheren Problemen wären eine gute Ergänzung. – Veedrac