public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/111077] New: atomic_ref compare_exchange_strong doesn't properly ignore padding bits
@ 2023-08-19 19:06 comexk at gmail dot com
  2023-08-19 19:36 ` [Bug c++/111077] " pinskia at gcc dot gnu.org
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: comexk at gmail dot com @ 2023-08-19 19:06 UTC (permalink / raw)
  To: gcc-bugs

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.]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2024-05-21  9:16 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-19 19:06 [Bug libstdc++/111077] New: atomic_ref compare_exchange_strong doesn't properly ignore padding bits comexk at gmail dot com
2023-08-19 19:36 ` [Bug c++/111077] " pinskia at gcc dot gnu.org
2023-08-19 20:07 ` pinskia at gcc dot gnu.org
2023-08-19 20:11 ` [Bug libstdc++/111077] " pinskia at gcc dot gnu.org
2023-08-19 20:14 ` pinskia at gcc dot gnu.org
2023-08-19 20:19 ` pinskia at gcc dot gnu.org
2023-08-20  7:16 ` redi at gcc dot gnu.org
2023-08-20  8:35 ` redi at gcc dot gnu.org
2023-09-01 15:02 ` cvs-commit at gcc dot gnu.org
2024-05-21  9:16 ` jakub at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).