Skip to content

Commit 20914fd

Browse files
authored
fix: use wrapping arithmetic in unsync fetch_add / fetch_sub (#17)
Plain `+` and `-` panic on overflow in debug builds, violating the wrap-on-overflow contract of `std::sync::atomic` integer types. Switch to `wrapping_add` / `wrapping_sub` to match stdlib semantics. Fixes #16
1 parent 2502e28 commit 20914fd

1 file changed

Lines changed: 39 additions & 3 deletions

File tree

src/atomic/unsync.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,12 @@ macro_rules! atomic_int {
362362

363363
/// Adds to the current value, returning the previous value.
364364
pub fn fetch_add(&self, val: $i, _: Ordering) -> $i {
365-
self.v.replace(self.v.get() + val)
365+
self.v.replace(self.v.get().wrapping_add(val))
366366
}
367367

368-
/// Subtract to the current value, returning the previous value.
368+
/// Subtract from the current value, returning the previous value.
369369
pub fn fetch_sub(&self, val: $i, _: Ordering) -> $i {
370-
self.v.replace(self.v.get() - val)
370+
self.v.replace(self.v.get().wrapping_sub(val))
371371
}
372372

373373
/// Bitwise "and" with the current value.
@@ -430,3 +430,39 @@ macro_rules! atomic_int {
430430
}
431431

432432
use atomic_int;
433+
434+
#[cfg(test)]
435+
mod tests {
436+
use super::*;
437+
use std::sync::atomic::Ordering::Relaxed;
438+
439+
#[test]
440+
fn atomic_u16_fetch_add_wraps() {
441+
let a = AtomicU16::new(u16::MAX);
442+
let old = a.fetch_add(1, Relaxed);
443+
assert_eq!(old, u16::MAX);
444+
assert_eq!(a.load(Relaxed), 0);
445+
}
446+
447+
#[test]
448+
fn atomic_u16_fetch_sub_wraps() {
449+
let a = AtomicU16::new(0);
450+
let old = a.fetch_sub(1, Relaxed);
451+
assert_eq!(old, 0);
452+
assert_eq!(a.load(Relaxed), u16::MAX);
453+
}
454+
455+
#[test]
456+
fn atomic_u8_fetch_add_wraps() {
457+
let a = AtomicU8::new(u8::MAX);
458+
assert_eq!(a.fetch_add(1, Relaxed), u8::MAX);
459+
assert_eq!(a.load(Relaxed), 0);
460+
}
461+
462+
#[test]
463+
fn atomic_i16_fetch_add_wraps() {
464+
let a = AtomicI16::new(i16::MAX);
465+
assert_eq!(a.fetch_add(1, Relaxed), i16::MAX);
466+
assert_eq!(a.load(Relaxed), i16::MIN);
467+
}
468+
}

0 commit comments

Comments
 (0)