libstdc++: Fix null pointer dereferences in __gnu_cxx::rope
authorJonathan Wakely <jwakely@redhat.com>
Wed, 2 Dec 2020 12:29:00 +0000 (12:29 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 2 Dec 2020 12:29:00 +0000 (12:29 +0000)
This fixes UBsan errors like:

/usr/include/c++/10/ext/ropeimpl.h:593:9: runtime error: member access within null pointer of type 'struct _RopeRep'
/usr/include/c++/10/ext/ropeimpl.h:593:9: runtime error: member call on null pointer of type 'struct _Rope_rep_base'
/usr/include/c++/10/ext/rope:556:17: runtime error: reference binding to null pointer of type 'struct allocator_type'
/usr/include/c++/10/ext/ropeimpl.h:593:9: runtime error: reference binding to null pointer of type 'struct allocator_type'
/usr/include/c++/10/ext/rope:1700:30: runtime error: member call on null pointer of type 'struct new_allocator'
/usr/include/c++/10/ext/new_allocator.h:105:29: runtime error: member call on null pointer of type 'struct new_allocator'
/usr/include/c++/10/ext/rope:1702:26: runtime error: reference binding to null pointer of type 'const struct allocator'
/usr/include/c++/10/bits/allocator.h:148:34: runtime error: reference binding to null pointer of type 'const struct new_allocator'
/usr/include/c++/10/ext/rope:1664:39: runtime error: reference binding to null pointer of type 'const struct allocator'
/usr/include/c++/10/ext/rope:1665:9: runtime error: reference binding to null pointer of type 'const struct allocator_type'
/usr/include/c++/10/ext/rope:725:36: runtime error: reference binding to null pointer of type 'const struct allocator_type'
/usr/include/c++/10/ext/rope:614:64: runtime error: reference binding to null pointer of type 'const struct allocator_type'

The problem is calling r->_M_get_allocator() when r is null.

libstdc++-v3/ChangeLog:

* include/ext/rope (rope::_S_concat_char_iter)
(rope::_S_destr_concat_char_iter): Add allocator parameter.
(rope::push_back, rope::append, rope::insert, operator+):
Pass allocator.
* include/ext/ropeimpl.h (rope::_S_concat_char_iter)
(rope::_S_destr_concat_char_iter): Add allocator parameter
and use it.
(_Rope_char_ref_proxy::operator=(_CharT)): Pass allocator.

libstdc++-v3/include/ext/rope
libstdc++-v3/include/ext/ropeimpl.h

index 8479acd8f74c04bb8b307b52ef9272b13b2a0e0f..de6ecdd524fad0b0e85d5f8ef9b9f82809468266 100644 (file)
@@ -1612,19 +1612,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       static _RopeRep* _S_concat_char_iter(_RopeRep* __r,
                                           const _CharT* __iter,
-                                          size_type __slen);
-      // Concatenate rope and char ptr, copying __s.
+                                          size_type __slen,
+                                          allocator_type& __a);
+      // Concatenate rope and char ptr, copying __iter.
       // Should really take an arbitrary iterator.
       // Result is counted in refcount.
       static _RopeRep* _S_destr_concat_char_iter(_RopeRep* __r,
                                                 const _CharT* __iter,
-                                                size_type __slen)
+                                                size_type __slen,
+                                                allocator_type& __a)
        // As above, but one reference to __r is about to be
        // destroyed.  Thus the pieces may be recycled if all
        // relevant reference counts are 1.
 #ifdef __GC
        // We can't really do anything since refcounts are unavailable.
-      { return _S_concat_char_iter(__r, __iter, __slen); }
+      { return _S_concat_char_iter(__r, __iter, __slen, __a); }
 #else
       ;
 #endif
@@ -1913,9 +1915,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       void
       push_back(_CharT __x)
       {
+       allocator_type __a = _M_get_allocator();
        _RopeRep* __old = this->_M_tree_ptr;
        this->_M_tree_ptr
-         = _S_destr_concat_char_iter(this->_M_tree_ptr, &__x, 1);
+         = _S_destr_concat_char_iter(this->_M_tree_ptr, &__x, 1, __a);
        _S_unref(__old);
       }
 
@@ -2115,8 +2118,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       rope&
       append(const _CharT* __iter, size_type __n)
       {
+       allocator_type __a = _M_get_allocator();
        _RopeRep* __result =
-         _S_destr_concat_char_iter(this->_M_tree_ptr, __iter, __n);
+         _S_destr_concat_char_iter(this->_M_tree_ptr, __iter, __n, __a);
        _S_unref(this->_M_tree_ptr);
        this->_M_tree_ptr = __result;
        return *this;
@@ -2133,8 +2137,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       rope&
       append(const _CharT* __s, const _CharT* __e)
       {
+       allocator_type __a = _M_get_allocator();
        _RopeRep* __result =
-         _S_destr_concat_char_iter(this->_M_tree_ptr, __s, __e - __s);
+         _S_destr_concat_char_iter(this->_M_tree_ptr, __s, __e - __s, __a);
        _S_unref(this->_M_tree_ptr);
        this->_M_tree_ptr = __result;
        return *this;
@@ -2156,8 +2161,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       rope&
       append(_CharT __c)
       {
+       allocator_type __a = _M_get_allocator();
        _RopeRep* __result =
-         _S_destr_concat_char_iter(this->_M_tree_ptr, &__c, 1);
+         _S_destr_concat_char_iter(this->_M_tree_ptr, &__c, 1, __a);
        _S_unref(this->_M_tree_ptr);
        this->_M_tree_ptr = __result;
        return *this;
@@ -2239,7 +2245,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _Self_destruct_ptr __left(_S_substring(this->_M_tree_ptr, 0, __p));
        _Self_destruct_ptr __right(_S_substring(this->_M_tree_ptr,
                                                __p, size()));
-       _Self_destruct_ptr __left_result(_S_concat_char_iter(__left, __i, __n));
+       _Self_destruct_ptr __left_result(_S_concat_char_iter(__left, __i, __n,
+                                                            _M_get_allocator()));
        // _S_ destr_concat_char_iter should be safe here.
        // But as it stands it's probably not a win, since __left
        // is likely to have additional references.
@@ -2843,8 +2850,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       typedef rope<_CharT, _Alloc> rope_type;
       std::size_t __rlen = rope_type::_S_char_ptr_len(__right);
+      _Alloc __a = __left.get_allocator();
       return rope_type(rope_type::_S_concat_char_iter(__left._M_tree_ptr,
-                                                     __right, __rlen));
+                                                     __right, __rlen, __a));
     }
 
   template <class _CharT, class _Alloc>
@@ -2861,8 +2869,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator+(const rope<_CharT, _Alloc>& __left, _CharT __right)
     {
       typedef rope<_CharT, _Alloc> rope_type;
+      _Alloc __a = __left.get_allocator();
       return rope_type(rope_type::_S_concat_char_iter(__left._M_tree_ptr,
-                                                     &__right, 1));
+                                                     &__right, 1, __a));
     }
 
   template <class _CharT, class _Alloc>
index c5d3a0c1aef195bb96cd7e495dedb403d380b0e5..e571847d2c55fc5db5a1813a078d16d2474f707a 100644 (file)
@@ -524,7 +524,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template <class _CharT, class _Alloc>
     typename rope<_CharT, _Alloc>::_RopeRep*
     rope<_CharT, _Alloc>::
-    _S_concat_char_iter(_RopeRep* __r, const _CharT*__s, std::size_t __slen)
+    _S_concat_char_iter(_RopeRep* __r, const _CharT*__s, std::size_t __slen,
+                       allocator_type& __a)
     {
       using std::size_t;
       _RopeRep* __result;
@@ -534,8 +535,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          return __r;
        }
       if (0 == __r)
-       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
-                                               __r->_M_get_allocator());
+       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __a);
       if (__r->_M_tag == __detail::_S_leaf
          && __r->_M_size + __slen <= size_t(_S_copy_max))
        {
@@ -564,8 +564,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              return __result;
            }
        }
-      _RopeRep* __nright =
-       __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->_M_get_allocator());
+      _RopeRep* __nright = __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __a);
       __try
        {
          __r->_M_ref_nonnil();
@@ -585,17 +584,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     typename rope<_CharT,_Alloc>::_RopeRep*
     rope<_CharT,_Alloc>::
     _S_destr_concat_char_iter(_RopeRep* __r, const _CharT* __s,
-                             std::size_t __slen)
+                             std::size_t __slen, allocator_type& __a)
     {
       using std::size_t;
       _RopeRep* __result;
       if (0 == __r)
-       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
-                                               __r->_M_get_allocator());
+       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __a);
       size_t __count = __r->_M_ref_count;
       size_t __orig_size = __r->_M_size;
       if (__count > 1)
-       return _S_concat_char_iter(__r, __s, __slen);
+       return _S_concat_char_iter(__r, __s, __slen, __a);
       if (0 == __slen)
        {
          __r->_M_ref_count = 2;      // One more than before
@@ -632,8 +630,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              return __r;
            }
        }
-      _RopeRep* __right =
-       __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->_M_get_allocator());
+      _RopeRep* __right = __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __a);
       __r->_M_ref_nonnil();
       __try
        { __result = _S_tree_concat(__r, __right); }
@@ -1500,9 +1497,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Self_destruct_ptr __left(_My_rope::_S_substring(__old, 0, _M_pos));
       _Self_destruct_ptr __right(_My_rope::_S_substring(__old, _M_pos + 1,
                                                        __old->_M_size));
+      typename _RopeRep::allocator_type __a = _M_root->_M_get_allocator();
       _Self_destruct_ptr __result_left(_My_rope::
                                       _S_destr_concat_char_iter(__left,
-                                                                &__c, 1));
+                                                                &__c, 1,
+                                                                __a));
 
       _RopeRep* __result = _My_rope::_S_concat(__result_left, __right);
 #ifndef __GC