+2014-09-29 François Dumont <fdumont@gcc.gnu.org>
+
+ PR libstdc++/62313
+ * include/debug/safe_base.h
+ (_Safe_iterator_base(const _Safe_iterator_base&)): Delete declaration.
+ (_Safe_iterator_base& operator=(const _Safe_iterator_base&)): Likewise.
+ * include/debug/safe_iterator.h (_Safe_iterator<>): Move normal iterator
+ before _Safe_iterator_base in memory. Lock before modifying the iterator
+ in numerous places.
+ * include/debug/safe_local_iterator.h
+ (_Safe_local_iterator_base(const _Safe_local_iterator_base&)): Delete
+ declaration.
+ (_Safe_local_iterator_base& operator=(const _Safe_local_iterator_base&)):
+ Likewise.
+ * include/debug/safe_unordered_base.h (_Safe_local_iterator<>): Move
+ normal iterator before _Safe_iterator_base in memory. Lock before
+ modifying the iterator in numerous places.
+ * include/debug/forward_list (_Safe_forward_list<>::_M_swap_aux): Adapt.
+ * include/debug/safe_sequence.tcc
+ (_Safe_sequence<>::_M_transfer_from_if): Adapt.
+
2014-09-25 Jonathan Wakely <jwakely@redhat.com>
DR 1339
for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;)
{
// Even iterator is cast to const_iterator, not a problem.
- const_iterator* __victim = static_cast<const_iterator*>(__iter);
+ _Safe_iterator_base* __victim_base = __iter;
+ const_iterator* __victim =
+ static_cast<const_iterator*>(__victim_base);
__iter = __iter->_M_next;
if (__victim->base() == __rseq._M_base().cbefore_begin())
{
__victim->_M_unlink();
- if (__lhs_iterators == __victim)
- __lhs_iterators = __victim->_M_next;
+ if (__lhs_iterators == __victim_base)
+ __lhs_iterators = __victim_base->_M_next;
if (__bbegin_its)
{
- __victim->_M_next = __bbegin_its;
- __bbegin_its->_M_prior = __victim;
+ __victim_base->_M_next = __bbegin_its;
+ __bbegin_its->_M_prior = __victim_base;
}
else
- __last_bbegin = __victim;
- __bbegin_its = __victim;
+ __last_bbegin = __victim_base;
+ __bbegin_its = __victim_base;
}
else
- __victim->_M_sequence = &__lhs;
+ __victim_base->_M_sequence = &__lhs;
}
if (__bbegin_its)
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
{ this->_M_attach(__x._M_sequence, __constant); }
- _Safe_iterator_base&
- operator=(const _Safe_iterator_base&);
-
- explicit
- _Safe_iterator_base(const _Safe_iterator_base&);
-
~_Safe_iterator_base() { this->_M_detach(); }
/** For use in _Safe_iterator. */
* %_Safe_iterator has member functions for iterator invalidation,
* attaching/detaching the iterator from sequences, and querying
* the iterator's state.
+ *
+ * Note that _Iterator must be the first base class so that it gets
+ * initialized before the iterator is being attached to the container's list
+ * of iterators and it is being detached before _Iterator get
+ * destroyed. Otherwise it would result in a data race.
*/
template<typename _Iterator, typename _Sequence>
- class _Safe_iterator : public _Safe_iterator_base
+ class _Safe_iterator
+ : private _Iterator,
+ public _Safe_iterator_base
{
- typedef _Safe_iterator _Self;
+ typedef _Iterator _Iter_base;
+ typedef _Safe_iterator_base _Safe_base;
typedef typename _Sequence::const_iterator _Const_iterator;
- /// The underlying iterator
- _Iterator _M_current;
-
/// Determine if this is a constant iterator.
bool
_M_constant() const
typedef std::iterator_traits<_Iterator> _Traits;
+ struct _Attach_single
+ { };
+
+ _Safe_iterator(const _Iterator& __i, _Safe_sequence_base* __seq,
+ _Attach_single)
+ _GLIBCXX_NOEXCEPT
+ : _Iter_base(__i)
+ { _M_attach_single(__seq); }
+
public:
typedef _Iterator iterator_type;
typedef typename _Traits::iterator_category iterator_category;
typedef typename _Traits::pointer pointer;
/// @post the iterator is singular and unattached
- _Safe_iterator() _GLIBCXX_NOEXCEPT : _M_current() { }
+ _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
/**
* @brief Safe iterator construction from an unsafe iterator and
* @pre @p seq is not NULL
* @post this is not singular
*/
- _Safe_iterator(const _Iterator& __i, const _Sequence* __seq)
+ _Safe_iterator(const _Iterator& __i, const _Safe_sequence_base* __seq)
_GLIBCXX_NOEXCEPT
- : _Safe_iterator_base(__seq, _M_constant()), _M_current(__i)
+ : _Iter_base(__i), _Safe_base(__seq, _M_constant())
{
- _GLIBCXX_DEBUG_VERIFY(! this->_M_singular(),
+ _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(),
_M_message(__msg_init_singular)
._M_iterator(*this, "this"));
}
* @brief Copy construction.
*/
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
- : _Safe_iterator_base(__x, _M_constant()), _M_current(__x._M_current)
+ : _Iter_base(__x.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
- || __x._M_current == _Iterator(),
+ || __x.base() == _Iterator(),
_M_message(__msg_init_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
+ _M_attach(__x._M_sequence);
}
#if __cplusplus >= 201103L
* @brief Move construction.
* @post __x is singular and unattached
*/
- _Safe_iterator(_Safe_iterator&& __x) noexcept : _M_current()
+ _Safe_iterator(_Safe_iterator&& __x) noexcept
+ : _Iter_base()
{
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
- || __x._M_current == _Iterator(),
+ || __x.base() == _Iterator(),
_M_message(__msg_init_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
- std::swap(_M_current, __x._M_current);
- this->_M_attach(__x._M_sequence);
+ _Safe_sequence_base* __seq = __x._M_sequence;
__x._M_detach();
+ std::swap(base(), __x.base());
+ _M_attach(__seq);
}
#endif
typename __gnu_cxx::__enable_if<(std::__are_same<_MutableIterator,
typename _Sequence::iterator::iterator_type>::__value),
_Sequence>::__type>& __x) _GLIBCXX_NOEXCEPT
- : _Safe_iterator_base(__x, _M_constant()), _M_current(__x.base())
+ : _Iter_base(__x.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_M_message(__msg_init_const_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
+ _M_attach(__x._M_sequence);
}
/**
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
- || __x._M_current == _Iterator(),
+ || __x.base() == _Iterator(),
_M_message(__msg_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
- _M_current = __x._M_current;
- this->_M_attach(__x._M_sequence);
+
+ if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() = __x.base();
+ _M_version = __x._M_sequence->_M_version;
+ }
+ else
+ {
+ _M_detach();
+ base() = __x.base();
+ _M_attach(__x._M_sequence);
+ }
+
return *this;
}
_M_message(__msg_self_move_assign)
._M_iterator(*this, "this"));
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
- || __x._M_current == _Iterator(),
+ || __x.base() == _Iterator(),
_M_message(__msg_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
- _M_current = __x._M_current;
- _M_attach(__x._M_sequence);
+
+ if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() = __x.base();
+ _M_version = __x._M_sequence->_M_version;
+ }
+ else
+ {
+ _M_detach();
+ base() = __x.base();
+ _M_attach(__x._M_sequence);
+ }
+
__x._M_detach();
- __x._M_current = _Iterator();
+ __x.base() = _Iterator();
return *this;
}
#endif
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
._M_iterator(*this, "this"));
- return *_M_current;
+ return *base();
}
/**
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
._M_iterator(*this, "this"));
- return std::__addressof(*_M_current);
+ return std::__addressof(*base());
}
// ------ Input iterator requirements ------
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
- ++_M_current;
+ __gnu_cxx::__scoped_lock(this->_M_get_mutex());
+ ++base();
return *this;
}
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
- _Safe_iterator __tmp(*this);
- ++_M_current;
- return __tmp;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ return _Safe_iterator(base()++, this->_M_sequence, _Attach_single());
}
// ------ Bidirectional iterator requirements ------
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
._M_iterator(*this, "this"));
- --_M_current;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ --base();
return *this;
}
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
._M_iterator(*this, "this"));
- _Safe_iterator __tmp(*this);
- --_M_current;
- return __tmp;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ return _Safe_iterator(base()--, this->_M_sequence, _Attach_single());
}
// ------ Random access iterator requirements ------
&& this->_M_can_advance(__n+1),
_M_message(__msg_iter_subscript_oob)
._M_iterator(*this)._M_integer(__n));
-
- return _M_current[__n];
+ return base()[__n];
}
_Safe_iterator&
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
_M_message(__msg_advance_oob)
._M_iterator(*this)._M_integer(__n));
- _M_current += __n;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() += __n;
return *this;
}
_Safe_iterator
operator+(const difference_type& __n) const _GLIBCXX_NOEXCEPT
{
- _Safe_iterator __tmp(*this);
- __tmp += __n;
- return __tmp;
+ _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
+ _M_message(__msg_advance_oob)
+ ._M_iterator(*this)._M_integer(__n));
+ return _Safe_iterator(base() + __n, this->_M_sequence);
}
_Safe_iterator&
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
_M_message(__msg_retreat_oob)
._M_iterator(*this)._M_integer(__n));
- _M_current += -__n;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() -= __n;
return *this;
}
_Safe_iterator
operator-(const difference_type& __n) const _GLIBCXX_NOEXCEPT
{
- _Safe_iterator __tmp(*this);
- __tmp -= __n;
- return __tmp;
+ _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
+ _M_message(__msg_retreat_oob)
+ ._M_iterator(*this)._M_integer(__n));
+ return _Safe_iterator(base() - __n, this->_M_sequence);
}
// ------ Utilities ------
/**
* @brief Return the underlying iterator
*/
- _Iterator
- base() const _GLIBCXX_NOEXCEPT { return _M_current; }
+ _Iterator&
+ base() _GLIBCXX_NOEXCEPT { return *this; }
+
+ const _Iterator&
+ base() const _GLIBCXX_NOEXCEPT { return *this; }
/**
* @brief Conversion to underlying non-debug iterator to allow
* better interaction with non-debug containers.
*/
- operator _Iterator() const _GLIBCXX_NOEXCEPT { return _M_current; }
+ operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
/** Attach iterator to the given sequence. */
void
_M_attach(_Safe_sequence_base* __seq)
- {
- _Safe_iterator_base::_M_attach(__seq, _M_constant());
- }
+ { _Safe_base::_M_attach(__seq, _M_constant()); }
/** Likewise, but not thread-safe. */
void
_M_attach_single(_Safe_sequence_base* __seq)
- {
- _Safe_iterator_base::_M_attach_single(__seq, _M_constant());
- }
+ { _Safe_base::_M_attach_single(__seq, _M_constant()); }
/// Is the iterator dereferenceable?
bool
* the iterator's state.
*/
template<typename _Iterator, typename _Sequence>
- class _Safe_local_iterator : public _Safe_local_iterator_base
+ class _Safe_local_iterator
+ : private _Iterator
+ , public _Safe_local_iterator_base
{
- typedef _Safe_local_iterator _Self;
+ typedef _Iterator _Iter_base;
+ typedef _Safe_local_iterator_base _Safe_base;
typedef typename _Sequence::const_local_iterator _Const_local_iterator;
typedef typename _Sequence::size_type size_type;
- /// The underlying iterator
- _Iterator _M_current;
-
/// Determine if this is a constant iterator.
bool
_M_constant() const
typedef std::iterator_traits<_Iterator> _Traits;
+ struct _Attach_single
+ { };
+
+ _Safe_local_iterator(const _Iterator& __i, _Safe_sequence_base* __cont,
+ _Attach_single) noexcept
+ : _Iter_base(__i)
+ { _M_attach_single(__cont); }
+
public:
typedef _Iterator iterator_type;
typedef typename _Traits::iterator_category iterator_category;
typedef typename _Traits::pointer pointer;
/// @post the iterator is singular and unattached
- _Safe_local_iterator() : _M_current() { }
+ _Safe_local_iterator() noexcept : _Iter_base() { }
/**
* @brief Safe iterator construction from an unsafe iterator and
* @pre @p seq is not NULL
* @post this is not singular
*/
- _Safe_local_iterator(const _Iterator& __i, const _Sequence* __seq)
- : _Safe_local_iterator_base(__seq, _M_constant()), _M_current(__i)
+ _Safe_local_iterator(const _Iterator& __i,
+ const _Safe_sequence_base* __cont)
+ : _Iter_base(__i), _Safe_base(__cont, _M_constant())
{
_GLIBCXX_DEBUG_VERIFY(!this->_M_singular(),
_M_message(__msg_init_singular)
/**
* @brief Copy construction.
*/
- _Safe_local_iterator(const _Safe_local_iterator& __x)
- : _Safe_local_iterator_base(__x, _M_constant()),
- _M_current(__x._M_current)
+ _Safe_local_iterator(const _Safe_local_iterator& __x) noexcept
+ : _Iter_base(__x.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_M_message(__msg_init_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
+ _M_attach(__x._M_sequence);
+ }
+
+ /**
+ * @brief Move construction.
+ * @post __x is singular and unattached
+ */
+ _Safe_local_iterator(_Safe_local_iterator&& __x) noexcept
+ : _Iter_base()
+ {
+ _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
+ || __x.base() == _Iterator(),
+ _M_message(__msg_init_copy_singular)
+ ._M_iterator(*this, "this")
+ ._M_iterator(__x, "other"));
+ auto __cont = __x._M_sequence;
+ __x._M_detach();
+ std::swap(base(), __x.base());
+ _M_attach(__cont);
}
/**
_MutableIterator,
typename _Sequence::local_iterator::iterator_type>::__value,
_Sequence>::__type>& __x)
- : _Safe_local_iterator_base(__x, _M_constant()),
- _M_current(__x.base())
+ : _Iter_base(__x.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_M_message(__msg_init_const_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
+ _M_attach(__x._M_sequence);
}
/**
_M_message(__msg_copy_singular)
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
- _M_current = __x._M_current;
- this->_M_attach(__x._M_sequence);
+
+ if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() = __x.base();
+ _M_version = __x._M_sequence->_M_version;
+ }
+ else
+ {
+ _M_detach();
+ base() = __x.base();
+ _M_attach(__x._M_sequence);
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment.
+ * @post __x is singular and unattached
+ */
+ _Safe_local_iterator&
+ operator=(_Safe_local_iterator&& __x) noexcept
+ {
+ _GLIBCXX_DEBUG_VERIFY(this != &__x,
+ _M_message(__msg_self_move_assign)
+ ._M_iterator(*this, "this"));
+ _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
+ || __x.base() == _Iterator(),
+ _M_message(__msg_copy_singular)
+ ._M_iterator(*this, "this")
+ ._M_iterator(__x, "other"));
+
+ if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ base() = __x.base();
+ _M_version = __x._M_sequence->_M_version;
+ }
+ else
+ {
+ _M_detach();
+ base() = __x.base();
+ _M_attach(__x._M_sequence);
+ }
+
+ __x._M_detach();
+ __x.base() = _Iterator();
return *this;
}
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
._M_iterator(*this, "this"));
- return *_M_current;
+ return *base();
}
/**
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
._M_iterator(*this, "this"));
- return std::__addressof(*_M_current);
+ return std::__addressof(*base());
}
// ------ Input iterator requirements ------
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
- ++_M_current;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ ++base();
return *this;
}
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
- _Safe_local_iterator __tmp(*this);
- ++_M_current;
- return __tmp;
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ return _Safe_local_iterator(base()++, this->_M_sequence,
+ _Attach_single());
}
// ------ Utilities ------
/**
* @brief Return the underlying iterator
*/
- _Iterator
- base() const { return _M_current; }
+ _Iterator&
+ base() noexcept { return *this; }
+
+ const _Iterator&
+ base() const noexcept { return *this; }
/**
* @brief Return the bucket
*/
size_type
- bucket() const { return _M_current._M_get_bucket(); }
+ bucket() const { return base()._M_get_bucket(); }
/**
* @brief Conversion to underlying non-debug iterator to allow
* better interaction with non-debug containers.
*/
- operator _Iterator() const { return _M_current; }
+ operator _Iterator() const { return *this; }
/** Attach iterator to the given sequence. */
void
_M_attach(_Safe_sequence_base* __seq)
- { _Safe_iterator_base::_M_attach(__seq, _M_constant()); }
+ { _Safe_base::_M_attach(__seq, _M_constant()); }
/** Likewise, but not thread-safe. */
void
_M_attach_single(_Safe_sequence_base* __seq)
- { _Safe_iterator_base::_M_attach_single(__seq, _M_constant()); }
+ { _Safe_base::_M_attach_single(__seq, _M_constant()); }
/// Is the iterator dereferenceable?
bool
for (_Safe_iterator_base* __iter = __from._M_iterators; __iter;)
{
- iterator* __victim = static_cast<iterator*>(__iter);
+ _Safe_iterator_base* __victim_base = __iter;
+ iterator* __victim = static_cast<iterator*>(__victim_base);
__iter = __iter->_M_next;
if (!__victim->_M_singular() && __pred(__victim->base()))
{
__victim->_M_detach_single();
if (__transfered_iterators)
{
- __victim->_M_next = __transfered_iterators;
- __transfered_iterators->_M_prior = __victim;
+ __victim_base->_M_next = __transfered_iterators;
+ __transfered_iterators->_M_prior = __victim_base;
}
else
- __last_iterator = __victim;
- __victim->_M_sequence = this;
- __victim->_M_version = this->_M_version;
- __transfered_iterators = __victim;
+ __last_iterator = __victim_base;
+ __victim_base->_M_sequence = this;
+ __victim_base->_M_version = this->_M_version;
+ __transfered_iterators = __victim_base;
}
}
for (_Safe_iterator_base* __iter2 = __from._M_const_iterators;
__iter2;)
{
- const_iterator* __victim = static_cast<const_iterator*>(__iter2);
+ _Safe_iterator_base* __victim_base = __iter2;
+ const_iterator* __victim =
+ static_cast<const_iterator*>(__victim_base);
__iter2 = __iter2->_M_next;
if (!__victim->_M_singular() && __pred(__victim->base()))
{
__victim->_M_detach_single();
if (__transfered_const_iterators)
{
- __victim->_M_next = __transfered_const_iterators;
- __transfered_const_iterators->_M_prior = __victim;
+ __victim_base->_M_next = __transfered_const_iterators;
+ __transfered_const_iterators->_M_prior = __victim_base;
}
else
__last_const_iterator = __victim;
- __victim->_M_sequence = this;
- __victim->_M_version = this->_M_version;
- __transfered_const_iterators = __victim;
+ __victim_base->_M_sequence = this;
+ __victim_base->_M_version = this->_M_version;
+ __transfered_const_iterators = __victim_base;
}
}
}
bool __constant)
{ this->_M_attach(__x._M_sequence, __constant); }
- _Safe_local_iterator_base&
- operator=(const _Safe_local_iterator_base&);
-
- explicit
- _Safe_local_iterator_base(const _Safe_local_iterator_base&);
-
~_Safe_local_iterator_base() { this->_M_detach(); }
_Safe_unordered_container_base*