Commit 672ce939 by Richard Henderson Committed by Richard Henderson

re PR c++/60272 (atomic<>::compare_exchange_weak has spurious store and can cause race conditions)

PR c++/60272

gcc/
	* builtins.c (expand_builtin_atomic_compare_exchange): Conditionalize
	on failure the store back into EXPECT.
libatomic/
	* cas_n.c (libat_compare_exchange): Conditionalize on failure
	the store back to EPTR.

From-SVN: r207966
parent 95ce7613
2014-02-20 Richard Henderson <rth@redhat.com>
PR c++/60272
* builtins.c (expand_builtin_atomic_compare_exchange): Conditionalize
on failure the store back into EXPECT.
2014-02-20 Chung-Lin Tang <cltang@codesourcery.com> 2014-02-20 Chung-Lin Tang <cltang@codesourcery.com>
Sandra Loosemore <sandra@codesourcery.com> Sandra Loosemore <sandra@codesourcery.com>
......
...@@ -5292,7 +5292,7 @@ static rtx ...@@ -5292,7 +5292,7 @@ static rtx
expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp, expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp,
rtx target) rtx target)
{ {
rtx expect, desired, mem, oldval; rtx expect, desired, mem, oldval, label;
enum memmodel success, failure; enum memmodel success, failure;
tree weak; tree weak;
bool is_weak; bool is_weak;
...@@ -5330,14 +5330,23 @@ expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp, ...@@ -5330,14 +5330,23 @@ expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp,
if (tree_fits_shwi_p (weak) && tree_to_shwi (weak) != 0) if (tree_fits_shwi_p (weak) && tree_to_shwi (weak) != 0)
is_weak = true; is_weak = true;
if (target == const0_rtx)
target = NULL;
oldval = expect; oldval = expect;
if (!expand_atomic_compare_and_swap ((target == const0_rtx ? NULL : &target),
&oldval, mem, oldval, desired, if (!expand_atomic_compare_and_swap (&target, &oldval, mem, oldval, desired,
is_weak, success, failure)) is_weak, success, failure))
return NULL_RTX; return NULL_RTX;
if (oldval != expect) /* Conditionally store back to EXPECT, lest we create a race condition
emit_move_insn (expect, oldval); with an improper store to memory. */
/* ??? With a rearrangement of atomics at the gimple level, we can handle
the normal case where EXPECT is totally private, i.e. a register. At
which point the store can be unconditional. */
label = gen_label_rtx ();
emit_cmp_and_jump_insns (target, const0_rtx, NE, NULL, VOIDmode, 1, label);
emit_move_insn (expect, oldval);
emit_label (label);
return target; return target;
} }
......
2014-02-20 Richard Henderson <rth@redhat.com>
PR c++/60272
* cas_n.c (libat_compare_exchange): Conditionalize on failure
the store back to EPTR.
2014-01-02 Richard Sandiford <rdsandiford@googlemail.com> 2014-01-02 Richard Sandiford <rdsandiford@googlemail.com>
Update copyright years Update copyright years
......
...@@ -51,10 +51,9 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval, ...@@ -51,10 +51,9 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
#if !DONE && N <= WORDSIZE && defined(atomic_compare_exchange_w) #if !DONE && N <= WORDSIZE && defined(atomic_compare_exchange_w)
bool bool
SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval, SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
int smodel, int fmodel UNUSED) int smodel, int fmodel)
{ {
UWORD mask, shift, weval, woldval, wnewval, t, *wptr; UWORD mask, shift, weval, woldval, wnewval, t, *wptr;
bool ret = false;
pre_barrier (smodel); pre_barrier (smodel);
...@@ -82,12 +81,13 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval, ...@@ -82,12 +81,13 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
} }
while (!atomic_compare_exchange_w (wptr, &woldval, t, true, while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED)); __ATOMIC_RELAXED, __ATOMIC_RELAXED));
ret = true; post_barrier (smodel);
return true;
failure: failure:
*eptr = woldval >> shift; *eptr = woldval >> shift;
post_barrier (fmodel);
post_barrier (smodel); return false;
return ret;
} }
#define DONE 1 #define DONE 1
...@@ -102,18 +102,17 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval, ...@@ -102,18 +102,17 @@ SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
{ {
UTYPE oldval; UTYPE oldval;
UWORD magic; UWORD magic;
bool ret = false; bool ret;
pre_seq_barrier (smodel); pre_seq_barrier (smodel);
magic = protect_start (mptr); magic = protect_start (mptr);
oldval = *mptr; oldval = *mptr;
if (oldval == *eptr) ret = (oldval == *eptr);
{ if (ret)
*mptr = newval; *mptr = newval;
ret = true; else
} *eptr = oldval;
*eptr = oldval;
protect_end (mptr, magic); protect_end (mptr, magic);
post_seq_barrier (smodel); post_seq_barrier (smodel);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment