[PATCH][_GLIBCXX_DEBUG] Fix COW basic_string checks

François Dumont frs.dumont@gmail.com
Thu Mar 26 21:46:09 GMT 2026


Hi

Here is the fix to the current COW basic_string issue now that I've 
removed the DR438 _GLIBCXX_DEBUG code.

I've also revisited the location of the debug checks so that for example 
on the append_neg.cc test case we have this assertion message with the 
cxx11 string:

In function:
     constexpr std::cxx11::basic_string<_CharT, _Traits, _Alloc>& std::
     cxx11::basic_string<_CharT, _Traits, _Alloc>::replace(const_iterator,
     const_iterator, _InputIterator, _InputIterator) [with _InputIterator =

so refering to the replace method. Whereas on the cow string:

In function:
     std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT,
     _Traits, _Alloc>::append(_InputIterator, _InputIterator) [with
     _InputIterator = gnu_debug::_Safe_iterator<gnu_cxx::

I plan to do something similar on cxx11 string. Let me know if useless.

     libstdc++: [_GLIBCXX_DEBUG] Fix COW basic_string checks

     In revision 698a6af5dcbae5d935bcda8a461dea8458c658dc the 
_GLIBCXX_DEBUG code
     for the Library Defect 438 has been removed for C++11 and after. 
But the COW
     basic_string implementation used when _GLIBCXX_USE_CXX11_ABI=0 was 
missing
     the _RequireInputIter constraint on a number method resulting in 
test failures.

     _RequireInputIter is now added where necessary. And _GLIBCXX_DEBUG 
checks have
     been added at the right place to benefit from more accurate 
assertion messages.

     libstdc++-v3/ChangeLog:

             * include/bits/cow_string.h [__cplusplus >= 201103L]
             (basic_string(_InputIte, _InputIte, const _Alloc&)): Add 
_RequireInputIter
             template parameter. Add 
__glibcxx_requires_valid_constructor_range call.
             (_M_replace_dispatch(_InputIte, _InputIte): New.
             (_M_replace_dispatch(iterator, iterator, _InputIte, 
_InputIte): New.
             [__cplusplus >= 201103L]
             (append(_InputIte, _InputIte)): Add _RequireInputIter 
template parameter.
             Add __glibcxx_requires_valid_constructor_range call. Use 
latter.
             (insert(iterator, _InputIte, _InputIte)): Likewise.
             (replace(iterator, iterator, _InputIte, _InputIte)): Likewise.
             (_S_construct(_InputIte, _InputIte, const _Alloc&)):  Add 
_RequireInputIter
             template parameter.
             * include/debug/debug.h 
(__glibcxx_requires_valid_construtor_range): New.
             * testsuite/21_strings/basic_string/debug/append_neg.cc: 
New test case.
             * testsuite/21_strings/basic_string/debug/assign_neg.cc: 
New test case.
             * testsuite/21_strings/basic_string/debug/construct_neg.cc: 
New test case.
             * testsuite/21_strings/basic_string/debug/insert_neg.cc: 
New test case.
             * testsuite/21_strings/basic_string/debug/replace_neg.cc: 
New test case.

Tested under Linux x64_86.

Ok to commit ?

François

-------------- next part --------------
diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h
index 6cf00224372..140afd03c43 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -721,10 +721,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @param  __end  End of range.
        *  @param  __a  Allocator to use (default is default allocator).
        */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string(_InputIterator __beg, _InputIterator __end,
 		     const _Alloc& __a = _Alloc())
-	: _M_dataplus(_S_construct(__beg, __end, __a), __a)
+	: _M_dataplus(_S_construct(
+	  __glibcxx_requires_valid_constructor_range(__beg, __end),
+	  __end, __a), __a)
 	{ }
 
 #ifdef __glibcxx_string_view // >= C++17
@@ -1391,10 +1398,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Appends characters in the range [__first,__last) to this string.
        */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	append(_InputIterator __first, _InputIterator __last)
-	{ return this->replace(_M_iend(), _M_iend(), __first, __last); }
+	{
+	  __glibcxx_requires_valid_range(__first, __last);
+	  return _M_replace_dispatch(__first, __last);
+	}
 
 #ifdef __glibcxx_string_view // >= C++17
       /**
@@ -1538,10 +1553,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Sets value of string to characters in the range [__first,__last).
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	assign(_InputIterator __first, _InputIterator __last)
-	{ return this->replace(_M_ibegin(), _M_iend(), __first, __last); }
+	{
+	  __glibcxx_requires_valid_range(__first, __last);
+	  return _M_replace_dispatch(__first, __last);
+	}
 
 #if __glibcxx_containers_ranges // C++ >= 23
       /**
@@ -1631,10 +1654,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  length_error is thrown.  The value of the string doesn't
        *  change if an error is thrown.
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	void
 	insert(iterator __p, _InputIterator __beg, _InputIterator __end)
-	{ this->replace(__p, __p, __beg, __end); }
+	{
+	  _GLIBCXX_DEBUG_PEDASSERT(_M_ibegin() <= __p && __p <= _M_iend());
+	  __glibcxx_requires_valid_range(__beg, __end);
+	  _M_replace_dispatch(__p, __p, __beg, __end);
+	}
 
 #if __glibcxx_containers_ranges // C++ >= 23
       /**
@@ -2117,7 +2149,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  The value of the string doesn't change if an error is
        *  thrown.
       */
-      template<class _InputIterator>
+#if __cplusplus >= 201103L
+      template<typename _InputIterator,
+	       typename = std::_RequireInputIter<_InputIterator>>
+#else
+      template<typename _InputIterator>
+#endif
 	basic_string&
 	replace(iterator __i1, iterator __i2,
 		_InputIterator __k1, _InputIterator __k2)
@@ -2125,8 +2162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _GLIBCXX_DEBUG_PEDASSERT(_M_ibegin() <= __i1 && __i1 <= __i2
 				   && __i2 <= _M_iend());
 	  __glibcxx_requires_valid_range(__k1, __k2);
-	  typedef typename std::__is_integer<_InputIterator>::__type _Integral;
-	  return _M_replace_dispatch(__i1, __i2, __k1, __k2, _Integral());
+	  return _M_replace_dispatch(__i1, __i2, __k1, __k2);
 	}
 
       // Specializations for the common case of pointer and iterator:
@@ -2270,17 +2306,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // C++17
 
     private:
+#if __cplusplus < 201103L
       template<class _Integer>
 	basic_string&
 	_M_replace_dispatch(iterator __i1, iterator __i2, _Integer __n,
 			    _Integer __val, __true_type)
 	{ return _M_replace_aux(__i1 - _M_ibegin(), __i2 - __i1, __n, __val); }
+#endif
 
       template<class _InputIterator>
 	basic_string&
 	_M_replace_dispatch(iterator __i1, iterator __i2, _InputIterator __k1,
 			    _InputIterator __k2, __false_type);
 
+      template<class _InputIterator>
+	basic_string&
+	_M_replace_dispatch(_InputIterator __first, _InputIterator __last)
+	{ return _M_replace_dispatch(_M_ibegin(), _M_iend(), __first, __last); }
+
+      template<class _InputIterator>
+	basic_string&
+	_M_replace_dispatch(iterator __i1, iterator __i2,
+			    _InputIterator __first, _InputIterator __last)
+	{
+#if __cplusplus >= 201103L
+	  using _Integral = std::__false_type;
+#else
+	  typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+#endif
+	  return _M_replace_dispatch(__i1, __i2, __first, __last, _Integral());
+	}
+
       basic_string&
       _M_replace_aux(size_type __pos1, size_type __n1, size_type __n2,
 		     _CharT __c);
@@ -2300,6 +2356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  return _S_construct(__beg, __end, __a, _Tag());
 	}
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<class _Integer>
@@ -2312,12 +2369,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static _CharT*
       _S_construct_aux_2(size_type __req, _CharT __c, const _Alloc& __a)
       { return _S_construct(__req, __c, __a); }
+#endif
 
-      template<class _InIterator>
+#if __cplusplus >= 201103L
+      template<typename _InIterator,
+	       typename = std::_RequireInputIter<_InIterator>>
+#else
+      template<typename _InIterator>
+#endif
 	static _CharT*
 	_S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a)
 	{
+#if __cplusplus >= 201103L
+	  using _Integral = std::__false_type;
+#else
 	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
+#endif
 	  return _S_construct_aux(__beg, __end, __a, _Integral());
 	}
 
diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h
index 5604f98e4d3..aabb9af2271 100644
--- a/libstdc++-v3/include/debug/debug.h
+++ b/libstdc++-v3/include/debug/debug.h
@@ -65,6 +65,8 @@ namespace __gnu_debug
 
 # define __glibcxx_requires_cond(_Cond,_Msg)
 # define __glibcxx_requires_valid_range(_First,_Last)
+# define __glibcxx_requires_valid_constructor_range(_First,_Last) \
+  _First
 # define __glibcxx_requires_can_increment(_First,_Size)
 # define __glibcxx_requires_can_increment_range(_First1,_Last1,_First2)
 # define __glibcxx_requires_can_decrement_range(_First1,_Last1,_First2)
@@ -92,6 +94,8 @@ namespace __gnu_debug
 # define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)
 # define __glibcxx_requires_valid_range(_First,_Last)	\
   __glibcxx_check_valid_range(_First,_Last)
+# define __glibcxx_requires_valid_constructor_range(_First,_Last) \
+  __glibcxx_check_valid_constructor_range(_First,_Last)
 # define __glibcxx_requires_can_increment(_First,_Size)	\
   __glibcxx_check_can_increment(_First,_Size)
 # define __glibcxx_requires_can_increment_range(_First1,_Last1,_First2)	\


More information about the Libstdc++ mailing list