https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111077
Bug ID: 111077 Summary: atomic_ref compare_exchange_strong doesn't properly ignore padding bits Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: comexk at gmail dot com Target Milestone: --- C++20 requires that the functions `std::atomic<T>::compare_exchange_strong` and `std::atomic_ref<T>::compare_exchange_strong` ignore any padding bits that exist in T. libstdc++ implements this by relying on the invariant that `std::atomic<T>` values in memory always have zeroed padding bits. All methods of `std::atomic<T>` that store values to memory (including the constructor) zero the padding bits first. Then, `std::atomic<T>::compare_exchange_strong` zeroes the padding bits of the `expected` value, allowing it to assume that the native atomic compare-exchange won't fail due to padding bits. However, this doesn't work correctly for `std::atomic_ref<T>`. All methods of `std::atomic_ref<T>` that store to memory do zero the padding bits. But what about the initial value of the object, before the first atomic_ref pointing to it was created? That value could be anything. As a result, this code (compiled with -std=c++20) incorrectly prints 0, even though the only difference between `value` and `expected` is in a padding byte: #include <atomic> #include <stdio.h> int main() { struct HasPadding { char a; short b; }; HasPadding value = {}; ((char *)&value)[1] = 0x42; // update padding byte HasPadding expected = {}; printf("%d\n", std::atomic_ref(value).compare_exchange_strong( expected, expected)); } This could be fixed by reimplementing `std::atomic_ref<T>::compare_exchange_strong` to use a loop, as in this pseudocode: bool compare_exchange_strong(std::atomic_ref<T> ref, T& expected, T desired) { T orig = expected; while (1) { if (ref.compare_exchange_weak_including_padding(expected, desired)) { return true; } if (!equal_ignoring_padding(orig, expected)) { return false; } } } [See also: https://github.com/rust-lang/unsafe-code-guidelines/issues/449#issuecomment-1677985851, which has a comparison of different compilers.]