From patchwork Thu Aug 30 10:29:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [libstdc++] Fix PR54172 Date: Thu, 30 Aug 2012 00:29:51 -0000 From: Thiago Macieira X-Patchwork-Id: 180812 Message-Id: <3027697.Y09XNY3VZT@tjmaciei-mobl2> To: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Hello The attached patch fixes a race condition in __cxa_guard_acquire, a regression from 4.6. When the code was refactored to use the new atomic intrinsics, the fact that __atomic_compare_exchange_n updates the "expected" variable with the current value was missed. That causes the loop to possibly overwrite a successful initialisation and re- start the initialisation phase. The bug report has a gdb trace with a watchpoint showing the guard variable transitioning 0 (uninit) -> 256 (pending) -> 1 (done) -> 256 (pending) -> 1 (done) This situation can happen if both CAS fail in given thread: the first because the other thread started the initialisation and the second because the initialisation succeeded. 2012-08-30 Thiago Macieira PR libstdc++/54172 * libsupc++/guard.cc (__cxa_guard_acquire): Don't compare_exchange from a finished state back to a waiting state. --- libstdc++-v3/libsupc++/guard.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libstdc++-v3/libsupc++/guard.cc b/libstdc++-v3/libsupc++/guard.cc index adc9608..4da9035 100644 --- a/libstdc++-v3/libsupc++/guard.cc +++ b/libstdc++-v3/libsupc++/guard.cc @@ -244,13 +244,13 @@ namespace __cxxabiv1 if (__gthread_active_p ()) { int *gi = (int *) (void *) g; - int expected(0); const int guard_bit = _GLIBCXX_GUARD_BIT; const int pending_bit = _GLIBCXX_GUARD_PENDING_BIT; const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT; while (1) { + int expected(0); if (__atomic_compare_exchange_n(gi, &expected, pending_bit, false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)) -- 1.7.11.4