On Mon, Sep 8, 2025 at 5:54 AM Jonathan Wakely <[email protected]> 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. > --- > This caused: Running /export/gnu/import/git/sources/gcc/gcc/testsuite/g++.dg/analyzer/analyzer.exp ... FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++14 at line 13 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++14 at line 18 (test for warnings, line 11) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++14 at line 19 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++14 at line 20 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++14 at line 21 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++17 at line 13 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++17 at line 19 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++17 at line 20 (test for warnings, line 12) FAIL: g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C -std=c++17 at line 21 (test for warnings, line 12) on Linux/x86-64. -- H.J.
