From 74270a546cf75aad5e2db642b4715728d4da7904 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 2 Dec 2020 12:29:00 +0000 Subject: [PATCH] libstdc++: Fix null pointer dereferences in __gnu_cxx::rope 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 | 31 +++++++++++++++++++---------- libstdc++-v3/include/ext/ropeimpl.h | 23 ++++++++++----------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/libstdc++-v3/include/ext/rope b/libstdc++-v3/include/ext/rope index 8479acd8f74..de6ecdd524f 100644 --- a/libstdc++-v3/include/ext/rope +++ b/libstdc++-v3/include/ext/rope @@ -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 @@ -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 diff --git a/libstdc++-v3/include/ext/ropeimpl.h b/libstdc++-v3/include/ext/ropeimpl.h index c5d3a0c1aef..e571847d2c5 100644 --- a/libstdc++-v3/include/ext/ropeimpl.h +++ b/libstdc++-v3/include/ext/ropeimpl.h @@ -524,7 +524,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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 -- 2.30.2