re PR libstdc++/59656 (weak_ptr::lock function crashes when compiling with -fno-excep...
authorJonathan Wakely <jwakely@redhat.com>
Tue, 28 Jan 2014 10:23:27 +0000 (10:23 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 28 Jan 2014 10:23:27 +0000 (10:23 +0000)
2014-01-28  Jonathan Wakely  <jwakely@redhat.com>
    Kyle Lippincott  <spectral@google.com>

PR libstdc++/59656
* include/bits/shared_ptr.h (shared_ptr): Add new non-throwing
constructor and grant friendship to weak_ptr.
(weak_ptr::lock()): Use new constructor.
* include/bits/shared_ptr_base.h
(_Sp_counted_base::_M_add_ref_lock_nothrow()): Declare new function
and define specializations.
(__shared_count): Add new non-throwing constructor.
(__shared_ptr): Add new non-throwing constructor and grant friendship
to __weak_ptr.
(__weak_ptr::lock()): Use new constructor.
* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error.
* testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise.

Co-Authored-By: Kyle Lippincott <spectral@google.com>
From-SVN: r207180

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/shared_ptr.h
libstdc++-v3/include/bits/shared_ptr_base.h
libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc

index da7083054978f6435f350f62e189b445dcd57881..4674e1f7318b0ea2578941c48d259a13001350c0 100644 (file)
@@ -1,3 +1,20 @@
+2014-01-28  Jonathan Wakely  <jwakely@redhat.com>
+           Kyle Lippincott  <spectral@google.com>
+
+       PR libstdc++/59656
+       * include/bits/shared_ptr.h (shared_ptr): Add new non-throwing
+       constructor and grant friendship to weak_ptr.
+       (weak_ptr::lock()): Use new constructor.
+       * include/bits/shared_ptr_base.h
+       (_Sp_counted_base::_M_add_ref_lock_nothrow()): Declare new function
+       and define specializations.
+       (__shared_count): Add new non-throwing constructor.
+       (__shared_ptr): Add new non-throwing constructor and grant friendship
+       to __weak_ptr.
+       (__weak_ptr::lock()): Use new constructor.
+       * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error.
+       * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise.
+
 2014-01-27  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/59215
index 8fcf710b3281942ee81a97abc2cb6f4088f32fe1..081d3bd3748d35e0b6e09c01b90878e341de025f 100644 (file)
@@ -319,6 +319,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Tp1, typename _Alloc, typename... _Args>
        friend shared_ptr<_Tp1>
        allocate_shared(const _Alloc& __a, _Args&&... __args);
+
+      // This constructor is non-standard, it is used by weak_ptr::lock().
+      shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t)
+      : __shared_ptr<_Tp>(__r, std::nothrow) { }
+
+      friend class weak_ptr<_Tp>;
     };
 
   // 20.7.2.2.7 shared_ptr comparisons
@@ -492,23 +498,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       shared_ptr<_Tp>
       lock() const noexcept
-      {
-#ifdef __GTHREADS
-       if (this->expired())
-         return shared_ptr<_Tp>();
-
-       __try
-         {
-           return shared_ptr<_Tp>(*this);
-         }
-       __catch(const bad_weak_ptr&)
-         {
-           return shared_ptr<_Tp>();
-         }
-#else
-       return this->expired() ? shared_ptr<_Tp>() : shared_ptr<_Tp>(*this);
-#endif
-      }
+      { return shared_ptr<_Tp>(*this, std::nothrow); }
     };
 
   // 20.7.2.3.6 weak_ptr specialized algorithms.
index 1c3a47dfb6e48c5b8725e01a503bf0f295877ee1..536df017d11d8781ae4586977016b2b4038c2e3e 100644 (file)
@@ -134,7 +134,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   
       void
       _M_add_ref_lock();
-      
+
+      bool
+      _M_add_ref_lock_nothrow();
+
       void
       _M_release() noexcept
       {
@@ -246,6 +249,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                          __ATOMIC_RELAXED));
     }
 
+  template<>
+    inline bool
+    _Sp_counted_base<_S_single>::
+    _M_add_ref_lock_nothrow()
+    {
+      if (_M_use_count == 0)
+       return false;
+      ++_M_use_count;
+      return true;
+    }
+
+  template<>
+    inline bool
+    _Sp_counted_base<_S_mutex>::
+    _M_add_ref_lock_nothrow()
+    {
+      __gnu_cxx::__scoped_lock sentry(*this);
+      if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
+       {
+         _M_use_count = 0;
+         return false;
+       }
+      return true;
+    }
+
+  template<>
+    inline bool
+    _Sp_counted_base<_S_atomic>::
+    _M_add_ref_lock_nothrow()
+    {
+      // Perform lock-free add-if-not-zero operation.
+      _Atomic_word __count = _M_get_use_count();
+      do
+       {
+         if (__count == 0)
+           return false;
+         // Replace the current counter value with the old value + 1, as
+         // long as it's not changed meanwhile.
+       }
+      while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
+                                         true, __ATOMIC_ACQ_REL,
+                                         __ATOMIC_RELAXED));
+      return true;
+    }
+
   template<>
     inline void
     _Sp_counted_base<_S_single>::_M_add_ref_copy()
@@ -609,6 +657,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
       explicit __shared_count(const __weak_count<_Lp>& __r);
 
+      // Does not throw if __r._M_get_use_count() == 0, caller must check.
+      explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t);
+
       ~__shared_count() noexcept
       {
        if (_M_pi != nullptr)
@@ -761,15 +812,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Now that __weak_count is defined we can define this constructor:
   template<_Lock_policy _Lp>
-    inline __shared_count<_Lp>:: __shared_count(const __weak_count<_Lp>& __r)
+    inline
+    __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r)
     : _M_pi(__r._M_pi)
     {
-      if (_M_pi != 0)
+      if (_M_pi != nullptr)
        _M_pi->_M_add_ref_lock();
       else
        __throw_bad_weak_ptr();
     }
 
+  // Now that __weak_count is defined we can define this constructor:
+  template<_Lock_policy _Lp>
+    inline
+    __shared_count<_Lp>::
+    __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t)
+    : _M_pi(__r._M_pi)
+    {
+      if (_M_pi != nullptr)
+       if (!_M_pi->_M_add_ref_lock_nothrow())
+         _M_pi = nullptr;
+    }
 
   // Support for enable_shared_from_this.
 
@@ -1077,6 +1140,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        friend __shared_ptr<_Tp1, _Lp1>
        __allocate_shared(const _Alloc& __a, _Args&&... __args);
 
+      // This constructor is used by __weak_ptr::lock() and
+      // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
+      __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t)
+      : _M_refcount(__r._M_refcount, std::nothrow)
+      {
+       _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
+      }
+
+      friend class __weak_ptr<_Tp, _Lp>;
+
     private:
       void*
       _M_get_deleter(const std::type_info& __ti) const noexcept
@@ -1322,31 +1395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       __shared_ptr<_Tp, _Lp>
       lock() const noexcept
-      {
-#ifdef __GTHREADS
-       // Optimization: avoid throw overhead.
-       if (expired())
-         return __shared_ptr<element_type, _Lp>();
-
-       __try
-         {
-           return __shared_ptr<element_type, _Lp>(*this);
-         }
-       __catch(const bad_weak_ptr&)
-         {
-           // Q: How can we get here?
-           // A: Another thread may have invalidated r after the
-           //    use_count test above.
-           return __shared_ptr<element_type, _Lp>();
-         }
-
-#else
-       // Optimization: avoid try/catch overhead when single threaded.
-       return expired() ? __shared_ptr<element_type, _Lp>()
-                        : __shared_ptr<element_type, _Lp>(*this);
-
-#endif
-      } // XXX MT
+      { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }
 
       long
       use_count() const noexcept
index 0a9864681468092b8045b2bbf367aeae4b140876..fbd8ccde6201a97fb220f1553d03be53c86916ff 100644 (file)
@@ -32,7 +32,7 @@ void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 812 }
+  // { dg-error "incomplete" "" { target *-*-* } 875 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
   // { dg-error "incomplete" "" { target *-*-* } 307 }
index 492d1db67ea3ebb682e11d0b5a1b1bc4e9a0cd8d..3f93a5e5249cd6dfe6d09e322e2645c92e165afd 100644 (file)
@@ -25,5 +25,5 @@
 void test01()
 {
   std::shared_ptr<void> p((void*)nullptr);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 811 }
+  // { dg-error "incomplete" "" { target *-*-* } 874 }
 }