public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/60272] New: atomic<>::compare_exchange_weak has spurious store and can cause race conditions
@ 2014-02-19 11:04 anthony.ajw at gmail dot com
  2014-02-19 11:19 ` [Bug c++/60272] " redi at gcc dot gnu.org
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: anthony.ajw at gmail dot com @ 2014-02-19 11:04 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60272

            Bug ID: 60272
           Summary: atomic<>::compare_exchange_weak has spurious store and
                    can cause race conditions
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: anthony.ajw at gmail dot com

Created attachment 32170
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=32170&action=edit
Sample code that demonstrates the problem

G++ 4.8.1 is producing incorrect code for std::atomic<>::compare_exchange_weak
on x86-64 linux.

In particular, if the exchange succeeds, then there is an additional spurious
store to the "expected" parameter after the exchange, which may race with other
threads and cause problems.

e.g.

#include <atomic>
struct Node { Node* next; };
void Push(std::atomic<Node*>& head, Node* node)
{
    node->next = head.load();
    while(!head.compare_exchange_weak(node->next, node))
        ;
}

When compiled with

g++-4.8 -S -std=c++11 -pthread -O3 t.cpp

the generated code is:

    movq    (%rdi), %rax
    movq    %rax, (%rsi)
    movq    (%rsi), %rax
    .p2align 4,,10
    .p2align 3
.L3:
    lock; cmpxchgq    %rsi, (%rdi)
    movq    %rax, (%rsi) *******
    jne    .L3
    rep; ret

The line marked ******* is an unconditional store to node->next in this
example, and will be executed even if the exchange is successful.

This will cause a race with code that uses the compare-exchange to order memory
operations.

e.g.

void Pop(std::atomic<Node*>& head){
    for(;;){
        Node* value=head.exchange(nullptr);
        if(value){
            delete value;
            break;
        }
    }
}

If the exchange successfully retrieves a non-null value, it should be OK to
delete it (assuming the node was allocated with new). However, if one thread is
calling Push() and is suspended after the CMPXCHG and before the line marked
******* is executed then another thread running Pop() can successfully complete
the exchange and call delete. When the first thread is resumed, the line marked
******* will then store to deallocated memory.

This is in contradiction to 29.6.5p21 of the C++ Standard, which states that
"expected" is only updated in the case of failure.


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

end of thread, other threads:[~2014-02-21  0:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-19 11:04 [Bug c++/60272] New: atomic<>::compare_exchange_weak has spurious store and can cause race conditions anthony.ajw at gmail dot com
2014-02-19 11:19 ` [Bug c++/60272] " redi at gcc dot gnu.org
2014-02-19 12:27 ` jakub at gcc dot gnu.org
2014-02-19 18:19 ` torvald at gcc dot gnu.org
2014-02-19 18:34 ` rth at gcc dot gnu.org
2014-02-20 17:44 ` rth at gcc dot gnu.org
2014-02-21  0:12 ` rth at gcc dot gnu.org
2014-02-21  0:14 ` rth at gcc dot gnu.org
2014-02-21  0:17 ` rth 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).