summaryrefslogtreecommitdiff
path: root/include/memory
diff options
context:
space:
mode:
authorMarshall Clow <mclow.lists@gmail.com>2016-05-18 17:50:13 +0000
committerMarshall Clow <mclow.lists@gmail.com>2016-05-18 17:50:13 +0000
commit2241cf0d5b5f18a51877b8fa4bcccde92fa675ad (patch)
tree9ca91c43dff172670095fb1e1dcd1853d79f9007 /include/memory
parenta3388c6bb2bbdd4d68683da0ef7bc52f98087434 (diff)
Change the control flow in atomic_compare_exchange_strong to avoid a potential deadlock.
When you assign a shared_ptr, the deleter gets called and assigned. In this routine, the assignment happens inside a critical section, which could (potentially) lead to a deadlock, if the deleter did something wonky. Now we swap the old value with an (empty) temporary shared_ptr, and then let the temporary delete the old value when it goes out of scope (after the lock has been released). This should fix PR#27724. Thanks to Hans Boehm for the bug report and the suggested fix. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@269965 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/memory')
-rw-r--r--include/memory3
1 files changed, 3 insertions, 0 deletions
diff --git a/include/memory b/include/memory
index 8378aef49..7627248a4 100644
--- a/include/memory
+++ b/include/memory
@@ -5541,14 +5541,17 @@ template <class _Tp>
bool
atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w)
{
+ shared_ptr<_Tp> __temp;
__sp_mut& __m = __get_sp_mut(__p);
__m.lock();
if (__p->__owner_equivalent(*__v))
{
+ _VSTD::swap(__temp, *__p);
*__p = __w;
__m.unlock();
return true;
}
+ _VSTD::swap(__temp, *__v);
*__v = *__p;
__m.unlock();
return false;