https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121148
Bug ID: 121148 Summary: Should use modular arithmetic for _Atomic_word Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: redi at gcc dot gnu.org Blocks: 71945 Target Milestone: --- The std::atomic<integral-type>::fetch_xxx members are required to never overflow: Remarks: [...] for signed integer types the result is as if the object value and parameters were converted to their corresponding unsigned types, the computation performed on those types, and the result converted back to the signed type. [Note 2 : There are no undefined results arising from the computation. — end note] So std::atomic<int>(INT_MAX).fetch_add(1) gives INT_MIN, not undefined overflow. Our atomic helper functions __gnu_cxx::__atomic_add and __gnu_cxx::__exchange_and_add should behave the same, to reduce surprises and avoid bugs. The default implementations are defined in terms of the __atomic_fetch_add built-in, so they're fine, but the single-threaded fallbacks and some alternative implementations can overflow. e.g. in include/ext/atomicity.h: inline _Atomic_word __attribute__((__always_inline__)) __exchange_and_add_single(_Atomic_word* __mem, int __val) { _Atomic_word __result = *__mem; *__mem += __val; return __result; } Since _Atomic_word is always a signed type (usually int, but long on 64-bit sparc), this should use an unsigned type for the arithmetic, e.g. _Atomic_word __result = *__mem; #if __cplusplus >= 201103L std::make_unsigned<_Atomic_word>::type __u; #else unsigned long long __u; #endif __u = __result; __u += __val; *__mem = __u; return __result; And similarly for __atomic_add. And we have this in config/cpu/generic/atomicity_mutex/atomicity.h _Atomic_word __attribute__ ((__unused__)) __exchange_and_add(volatile _Atomic_word* __mem, int __val) throw () { __gnu_cxx::__scoped_lock sentry(get_atomic_mutex()); _Atomic_word __result; __result = *__mem; *__mem += __val; return __result; } This one should just be: __gnu_cxx::__scoped_lock sentry(get_atomic_mutex()); return __gnu_cxx::__exchange_and_add_single(__mem, __val); So that we don't need to repeat the logic. Referenced Bugs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71945 [Bug 71945] Integer overflow in use counter of shared pointers