Skip to content

Commit

Permalink
Merge #781
Browse files Browse the repository at this point in the history
781: Fix unsoundness of AtomicCell<*64> arithmetics on 32-bit targets that support Atomic*64 r=taiki-e a=taiki-e

The alignment of u64/i64 on a 32-bit target can be smaller than AtomicU64/AtomicI64.

32-bit targets without Atomic*64 (#767) and 64-bit targets are not affected by this issue.

Co-authored-by: Taiki Endo <te316e89@gmail.com>
  • Loading branch information
bors[bot] and taiki-e committed Feb 5, 2022
2 parents be6ff29 + f7c378b commit 924436c
Showing 1 changed file with 90 additions and 10 deletions.
100 changes: 90 additions & 10 deletions crossbeam-utils/src/atomic/atomic_cell.rs
Expand Up @@ -465,8 +465,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_add(&self, val: $t) -> $t {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_add(val, Ordering::AcqRel)
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_add(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = value.wrapping_add(val);
old
}
}
}

/// Decrements the current value by `val` and returns the previous value.
Expand All @@ -485,8 +501,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_sub(&self, val: $t) -> $t {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_sub(val, Ordering::AcqRel)
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_sub(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = value.wrapping_sub(val);
old
}
}
}

/// Applies bitwise "and" to the current value and returns the previous value.
Expand All @@ -503,8 +535,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_and(&self, val: $t) -> $t {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_and(val, Ordering::AcqRel)
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_and(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value &= val;
old
}
}
}

/// Applies bitwise "or" to the current value and returns the previous value.
Expand All @@ -521,8 +569,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_or(&self, val: $t) -> $t {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_or(val, Ordering::AcqRel)
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_or(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value |= val;
old
}
}
}

/// Applies bitwise "xor" to the current value and returns the previous value.
Expand All @@ -539,8 +603,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_xor(&self, val: $t) -> $t {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_xor(val, Ordering::AcqRel)
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_xor(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value ^= val;
old
}
}
}
}
};
Expand Down

0 comments on commit 924436c

Please sign in to comment.