re PR libstdc++/62313 (Data race in debug iterators)
authorFrançois Dumont <fdumont@gcc.gnu.org>
Mon, 29 Sep 2014 21:22:17 +0000 (21:22 +0000)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Mon, 29 Sep 2014 21:22:17 +0000 (21:22 +0000)
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.

From-SVN: r215693

libstdc++-v3/ChangeLog
libstdc++-v3/include/debug/forward_list
libstdc++-v3/include/debug/safe_base.h
libstdc++-v3/include/debug/safe_iterator.h
libstdc++-v3/include/debug/safe_local_iterator.h
libstdc++-v3/include/debug/safe_sequence.tcc
libstdc++-v3/include/debug/safe_unordered_base.h

index f4478235623a4d4801534b5d2436a05e28e1985a..6560372986fc9753327c8453859a02a78edade5a 100644 (file)
@@ -1,3 +1,24 @@
+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
index c67fb464860ce5ba29b84b7addc974b3712d574e..a46f6d44760d022e194200360461af05038b3127 100644 (file)
@@ -86,24 +86,26 @@ namespace __gnu_debug
       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)
index fc589159a37d6462eaf363402adef9127dddc90c..35e399dc5350516574711f1404640e69c66dce0a 100644 (file)
@@ -95,12 +95,6 @@ namespace __gnu_debug
     : _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. */
index b6f136322f47414c834afda769da72e01b77ac94..8083ed317194822b036f9d2442ee76192e6f54a5 100644 (file)
@@ -109,16 +109,21 @@ namespace __gnu_debug
    *  %_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
@@ -126,6 +131,15 @@ namespace __gnu_debug
 
       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;
@@ -135,7 +149,7 @@ namespace __gnu_debug
       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
@@ -144,11 +158,11 @@ namespace __gnu_debug
        * @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"));
       }
@@ -157,15 +171,16 @@ namespace __gnu_debug
        * @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
@@ -173,16 +188,18 @@ namespace __gnu_debug
        * @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
 
@@ -196,7 +213,7 @@ namespace __gnu_debug
          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?
@@ -205,6 +222,7 @@ namespace __gnu_debug
                                _M_message(__msg_init_const_singular)
                                ._M_iterator(*this, "this")
                                ._M_iterator(__x, "other"));
+         _M_attach(__x._M_sequence);
        }
 
       /**
@@ -216,12 +234,24 @@ namespace __gnu_debug
        // _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;
       }
 
@@ -237,14 +267,26 @@ namespace __gnu_debug
                              _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
@@ -259,7 +301,7 @@ namespace __gnu_debug
        _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
                              _M_message(__msg_bad_deref)
                              ._M_iterator(*this, "this"));
-       return *_M_current;
+       return *base();
       }
 
       /**
@@ -273,7 +315,7 @@ namespace __gnu_debug
        _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 ------
@@ -287,7 +329,8 @@ namespace __gnu_debug
        _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;
       }
 
@@ -301,9 +344,8 @@ namespace __gnu_debug
        _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 ------
@@ -317,7 +359,8 @@ namespace __gnu_debug
        _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;
       }
 
@@ -331,9 +374,8 @@ namespace __gnu_debug
        _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 ------
@@ -344,8 +386,7 @@ namespace __gnu_debug
                              && 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&
@@ -354,16 +395,18 @@ namespace __gnu_debug
        _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&
@@ -372,44 +415,45 @@ namespace __gnu_debug
        _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
index 50da161ebce50dbc43031078881768a329bb860f..8fe16919c0294a2cd9ff3b57bffee6de8f1b73e3 100644 (file)
@@ -49,15 +49,15 @@ namespace __gnu_debug
    *  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
@@ -68,6 +68,14 @@ namespace __gnu_debug
 
       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;
@@ -77,7 +85,7 @@ namespace __gnu_debug
       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
@@ -86,8 +94,9 @@ namespace __gnu_debug
        * @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)
@@ -97,9 +106,8 @@ namespace __gnu_debug
       /**
        * @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?
@@ -108,6 +116,25 @@ namespace __gnu_debug
                              _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);
       }
 
       /**
@@ -121,8 +148,7 @@ namespace __gnu_debug
              _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?
@@ -131,6 +157,7 @@ namespace __gnu_debug
                                _M_message(__msg_init_const_singular)
                                ._M_iterator(*this, "this")
                                ._M_iterator(__x, "other"));
+         _M_attach(__x._M_sequence);
        }
 
       /**
@@ -146,8 +173,54 @@ namespace __gnu_debug
                              _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;
       }
 
@@ -161,7 +234,7 @@ namespace __gnu_debug
        _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
                              _M_message(__msg_bad_deref)
                              ._M_iterator(*this, "this"));
-       return *_M_current;
+       return *base();
       }
 
       /**
@@ -175,7 +248,7 @@ namespace __gnu_debug
        _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 ------
@@ -189,7 +262,8 @@ namespace __gnu_debug
        _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;
       }
 
@@ -203,39 +277,42 @@ namespace __gnu_debug
        _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
index 5fef446359e90a6f7e05a388c7f16be73b195a03..da9482a9443a2098ea83421a5bd339fe777aeff2 100644 (file)
@@ -81,42 +81,45 @@ namespace __gnu_debug
 
          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;
                }
            }
        }
index 31c5c894cc14a51235475140006f0d2b8ef1e151..380d7fe86020f6d0022100d72b1ee1c6a2e5d255 100644 (file)
@@ -71,12 +71,6 @@ namespace __gnu_debug
                              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*