C++ Logo

std-discussion

Advanced search

Re: Ordering semantics of compare_exchange_weak on spurious failure

From: Nate Eldredge <nate_at_[hidden]>
Date: Tue, 31 Mar 2026 15:51:26 +0000
> On Mar 31, 2026, at 01:55, Andrey Semashev via Std-Discussion <std-discussion_at_[hidden]> wrote:
>
> On 31 Mar 2026 07:11, Nate Eldredge via Std-Discussion wrote:
>> I was looking at the description of `std::atomic::compare_exchange_weak`
>> in [atomics.types.operations p21-28] (https://eel.is/c++draft/
>> atomics.types.operations#21 <https://eel.is/c++draft/
>> atomics.types.operations#21>), and it seems to be a bit ambiguous on the
>> ordering semantics of spurious failure.
>>
>> Recall that `compare_exchange_weak` can be passed two `memory_order`
>> arguments, `success` and `failure`. From the naming, I presume that in
>> case of spurious failure, the `failure` ordering is meant to be applied.
>> (Example of clang doing so: https://godbolt.org/z/613P4WMhd.) However,
>> this is not actually stated.
>>
>> Ordering is only mentioned in p23 ("Effects"), which although it
>> supposedly applies to both compare_exchange_strong and
>> compare_exchange_weak, actually only describes the strong semantics. It
>> does not allow for spurious failures, which are carved out later by p27
>> ("Remarks"). Paragraph p23 says:
>>
>> "If and only if the comparison is true, memory is affected according to
>> the value of success, and if the comparison is false, memory is affected
>> according to the value of failure."
>>
>> If we read this literally, then spurious failure ought to follow the
>> success ordering, because the comparison is true in that case, and p27
>> doesn't say anything to contradict it. But that doesn't seem to be
>> what's intended.
>
> Consider what is referred to as a "spurious failure", which is defined
> in p27 (https://eel.is/c++draft/atomics.types.operations#27):
>
> Remarks: A weak compare-and-exchange operation may fail spuriously.
> That is, even when the contents of memory referred to by expected and
> this are equal, it may return false and store back to expected the
> same memory contents that were originally there.
>
> So, the behavior in the case of a spurious failure would be equivalent
> to that of when the comparison legitimately returns false.

I certainly agree that's what's intended, but "equivalent" is not what p27 actually says. It says that on spurious failure, `false` is returned and `expected` is stored to. Those are only two of the three things that p23 says will happen when the comparison is false; the third is the ordering of memory according to `failure`, and that one's not mentioned by p27.

There is another (unrelated) issue raised by that passage. Suppose `expected` contains an object whose value representation agrees with `*this`, but whose padding bits differ; the comparison returns `true` in this case. Suppose the compare-exchange then fails spuriously. Is `expected` then modified to have the same padding bits that were in `*this`? The phrasing "same memory contents" is ambiguous as to whether it means "same object representation" or "same value representation". Indeed, "memory contents" is not formally defined or used anywhere else in the Standard.

If anything, using the phrase "memory contents" instead of "value" makes it sound like the object representation is intended; i.e. the padding bits of `expected` should not be changed on spurious failure. But in at least one actual implementation, they are: e.g. https://godbolt.org/z/qndYx9hE5 , where [sp,8] is a copy of `expected` with padding bits cleared to zero, and this is stored back to `expected` at .L6, which is reached on both legitimate and spurious failure.


Received on 2026-03-31 15:51:31