Commit 156b60e0 by Jonathan Wakely Committed by Jonathan Wakely

re PR libstdc++/59656 (weak_ptr::lock function crashes when compiling with -fno-exceptions flag)

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
parent 9ec2d2c1
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> 2014-01-27 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/59215 PR libstdc++/59215
......
...@@ -319,6 +319,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -319,6 +319,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp1, typename _Alloc, typename... _Args> template<typename _Tp1, typename _Alloc, typename... _Args>
friend shared_ptr<_Tp1> friend shared_ptr<_Tp1>
allocate_shared(const _Alloc& __a, _Args&&... __args); 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 // 20.7.2.2.7 shared_ptr comparisons
...@@ -492,23 +498,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -492,23 +498,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
shared_ptr<_Tp> shared_ptr<_Tp>
lock() const noexcept lock() const noexcept
{ { return shared_ptr<_Tp>(*this, std::nothrow); }
#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
}
}; };
// 20.7.2.3.6 weak_ptr specialized algorithms. // 20.7.2.3.6 weak_ptr specialized algorithms.
......
...@@ -134,7 +134,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -134,7 +134,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void void
_M_add_ref_lock(); _M_add_ref_lock();
bool
_M_add_ref_lock_nothrow();
void void
_M_release() noexcept _M_release() noexcept
{ {
...@@ -247,6 +250,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -247,6 +250,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<> 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 inline void
_Sp_counted_base<_S_single>::_M_add_ref_copy() _Sp_counted_base<_S_single>::_M_add_ref_copy()
{ ++_M_use_count; } { ++_M_use_count; }
...@@ -609,6 +657,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -609,6 +657,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Throw bad_weak_ptr when __r._M_get_use_count() == 0. // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
explicit __shared_count(const __weak_count<_Lp>& __r); 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 ~__shared_count() noexcept
{ {
if (_M_pi != nullptr) if (_M_pi != nullptr)
...@@ -761,15 +812,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -761,15 +812,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Now that __weak_count is defined we can define this constructor: // Now that __weak_count is defined we can define this constructor:
template<_Lock_policy _Lp> 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) : _M_pi(__r._M_pi)
{ {
if (_M_pi != 0) if (_M_pi != nullptr)
_M_pi->_M_add_ref_lock(); _M_pi->_M_add_ref_lock();
else else
__throw_bad_weak_ptr(); __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. // Support for enable_shared_from_this.
...@@ -1077,6 +1140,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1077,6 +1140,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend __shared_ptr<_Tp1, _Lp1> friend __shared_ptr<_Tp1, _Lp1>
__allocate_shared(const _Alloc& __a, _Args&&... __args); __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: private:
void* void*
_M_get_deleter(const std::type_info& __ti) const noexcept _M_get_deleter(const std::type_info& __ti) const noexcept
...@@ -1322,31 +1395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1322,31 +1395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__shared_ptr<_Tp, _Lp> __shared_ptr<_Tp, _Lp>
lock() const noexcept lock() const noexcept
{ { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }
#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
long long
use_count() const noexcept use_count() const noexcept
......
...@@ -32,7 +32,7 @@ void test01() ...@@ -32,7 +32,7 @@ void test01()
{ {
X* px = 0; X* px = 0;
std::shared_ptr<X> p1(px); // { dg-error "here" } 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" } std::shared_ptr<X> p9(ap()); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 307 } // { dg-error "incomplete" "" { target *-*-* } 307 }
......
...@@ -25,5 +25,5 @@ ...@@ -25,5 +25,5 @@
void test01() void test01()
{ {
std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" } std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 811 } // { dg-error "incomplete" "" { target *-*-* } 874 }
} }
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