On Mon, Sep 08, 2025 at 01:35:59PM +0100, Jonathan Wakely wrote: > The standard requires that std::atomic<integral-type>::fetch_add does > not have undefined behaviour for signed overflow, instead it wraps like > unsigned integers. The compiler ensures this is true for the atomic > built-ins that std::atomic uses, but it's not currently true for the > __gnu_cxx::__exchange_and_add and __gnu_cxx::__atomic_add functions > defined in libstdc++, which operate on type _Atomic_word. > > For the inline __exchange_and_add_single function (used when there's > only one thread in the process), we can copy the value to an unsigned > long and do the addition on that, then assign it back to the > _Atomic_word variable. > > The __exchange_and_add in config/cpu/generic/atomicity_mutex/atomicity.h > locks a mutex and then performs exactly the same steps as > __exchange_and_add_single. Calling __exchange_and_add_single instead of > duplicating the code benefits from the fix just made to > __exchange_and_add_single. > > For the remaining config/cpu/$arch/atomicity.h implementations, they > either use inline assembly which uses wrapping instructions (so no > changes needed), or we can fix them by compiling with -fwrapv. > > After ths change, UBsan no longer gives an error for: > > _Atomic_word i = INT_MAX; > __gnu_cxx::__exchange_and_add_dispatch(&i, 1); > > /usr/include/c++/14/ext/atomicity.h:85:12: runtime error: signed integer > overflow: 2147483647 + 1 cannot be represented in type 'int' > > libstdc++-v3/ChangeLog: > > PR libstdc++/121148 > * config/cpu/generic/atomicity_mutex/atomicity.h > (__exchange_and_add): Call __exchange_and_add_single. > * include/ext/atomicity.h (__exchange_and_add_single): Use an > unsigned type for the addition. > * libsupc++/Makefile.am (atomicity.o): Compile with -fwrapv. > * libsupc++/Makefile.in: Regenerate. > --- > > v2: no changes to this first patch in the series. > > Tested powerpc64le-linux. > > .../cpu/generic/atomicity_mutex/atomicity.h | 5 +-- > libstdc++-v3/include/ext/atomicity.h | 35 +++++++++++++++++-- > libstdc++-v3/libsupc++/Makefile.am | 5 +++ > libstdc++-v3/libsupc++/Makefile.in | 5 +++ > 4 files changed, 44 insertions(+), 6 deletions(-) > > diff --git a/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h > b/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h > index b1328c025bcc..7d5772d54840 100644 > --- a/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h > +++ b/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h > @@ -44,10 +44,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > __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; > + return __gnu_cxx::__exchange_and_add_single(__mem, __val); > } >
Hi Jonathan, This broke the build for pru-unknown-elf target. I suspect it's either because it uses newlib instead of glibc. Or because this target does not define its own atomic ops. The error is: atomicity.cc: In function ‘_Atomic_word __gnu_cxx::__exchange_and_add(volatile _Atomic_word*, int)’: atomicity.cc:47:49: error: invalid conversion from ‘volatile _Atomic_word*’ {aka ‘volatile int*’} to ‘_Atomic_word*’ {aka ‘int*’} [-fpermissive] 47 | return __gnu_cxx::__exchange_and_add_single(__mem, __val); | ^~~~~ | | | volatile _Atomic_word* {aka volatile int*} In file included from atomicity.cc:25: /home/dinux/projects/pru/testbot-workspace/pru-gcc-build/pru/libstdc++-v3/include/ext/atomicity.h:95:43: note: initializing argument 1 of ‘_Atomic_word __gnu_cxx::__exchange_and_add_single(_Atomic_word*, int)’ 95 | __exchange_and_add_single(_Atomic_word* __mem, int __val) | ~~~~~~~~~~~~~~^~~~~ Regards, Dimitar