diff options
author | Marshall Clow <mclow.lists@gmail.com> | 2016-05-18 17:50:13 +0000 |
---|---|---|
committer | Marshall Clow <mclow.lists@gmail.com> | 2016-05-18 17:50:13 +0000 |
commit | 2241cf0d5b5f18a51877b8fa4bcccde92fa675ad (patch) | |
tree | 9ca91c43dff172670095fb1e1dcd1853d79f9007 /include/memory | |
parent | a3388c6bb2bbdd4d68683da0ef7bc52f98087434 (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/memory | 3 |
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; |