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.

Reply via email to