New can_[in,de]crement_range debug checks

Message ID 43e32319-c5a6-90ce-5b28-1e9273992a7e@gmail.com
State New
Headers show
Series
  • New can_[in,de]crement_range debug checks
Related show

Commit Message

François Dumont June 11, 2018, 7:26 p.m.
Hi

     If not told otherwise I plan to commit attached patch tomorrow evening.

     It is adding new Debug checks to find out if an output iterator 
will always be reachable while looping on an input range. Note that this 
check was already done previously by checking if the iterator was 
[in,de]crementable but it will now assert before any operation take 
place. I also need it in order to remove debug layer on the output 
iterator in a future patch.

     I am also adding some tests on the std::equal algorithm because I 
plan to apply those macros to this algo too but users can append a 
special value at the end of the 2nd range to make sure it will never go 
beyond this position. Some tests are doing this and was triggering the 
Debug check.

     * include/debug/macros.h (__glibcxx_check_can_increment_range): New.
     (__glibcxx_check_can_decrement_range): New.
     * include/debug/debug.h (__glibcxx_requires_can_increment_range): New.
     (__glibcxx_requires_can_decrement_range): New.
     * include/bits/stl_algobase.h (std::copy(_II, _II, _OI)): Use
     __glibcxx_requires_can_increment_range.
     (std::move(_II, _II, _OI)): Likewise.
     (std::copy_backward(_BI, _BI, _BI2)): Use
     __glibcxx_requires_can_decrement_range.
     (std::move_backward(_BI, _BI, _BI2)): Likewise.
     * testsuite/25_algorithms/copy_backward/debug/1_neg.cc: New.
     * testsuite/25_algorithms/copy_backward/debug/2_neg.cc: New.
     * testsuite/25_algorithms/copy_backward/debug/3_neg.cc: New.
     * testsuite/25_algorithms/equal/debug/1_neg.cc: New.
     * testsuite/25_algorithms/equal/debug/2_neg.cc: New.
     * testsuite/25_algorithms/equal/debug/3_neg.cc: New.

Tested under Linux x86_64, normal and debug modes.

François

Patch

diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index bbc5774..d429943 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -449,11 +449,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_function_requires(_InputIteratorConcept<_II>)
       __glibcxx_function_requires(_OutputIteratorConcept<_OI,
 	    typename iterator_traits<_II>::value_type>)
-      __glibcxx_requires_valid_range(__first, __last);
+      __glibcxx_requires_can_increment_range(__first, __last, __result);
 
-      return (std::__copy_move_a2<__is_move_iterator<_II>::__value>
-	      (std::__miter_base(__first), std::__miter_base(__last),
-	       __result));
+      return std::__copy_move_a2<__is_move_iterator<_II>::__value>
+	     (std::__miter_base(__first), std::__miter_base(__last), __result);
     }
 
 #if __cplusplus >= 201103L
@@ -482,7 +481,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_function_requires(_InputIteratorConcept<_II>)
       __glibcxx_function_requires(_OutputIteratorConcept<_OI,
 	    typename iterator_traits<_II>::value_type>)
-      __glibcxx_requires_valid_range(__first, __last);
+      __glibcxx_requires_can_increment_range(__first, __last, __result);
 
       return std::__copy_move_a2<true>(std::__miter_base(__first),
 				       std::__miter_base(__last), __result);
@@ -627,11 +626,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_function_requires(_ConvertibleConcept<
 	    typename iterator_traits<_BI1>::value_type,
 	    typename iterator_traits<_BI2>::value_type>)
-      __glibcxx_requires_valid_range(__first, __last);
+      __glibcxx_requires_can_decrement_range(__first, __last, __result);
 
-      return (std::__copy_move_backward_a2<__is_move_iterator<_BI1>::__value>
-	      (std::__miter_base(__first), std::__miter_base(__last),
-	       __result));
+      return std::__copy_move_backward_a2<__is_move_iterator<_BI1>::__value>
+	     (std::__miter_base(__first), std::__miter_base(__last), __result);
     }
 
 #if __cplusplus >= 201103L
@@ -663,7 +661,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_function_requires(_ConvertibleConcept<
 	    typename iterator_traits<_BI1>::value_type,
 	    typename iterator_traits<_BI2>::value_type>)
-      __glibcxx_requires_valid_range(__first, __last);
+      __glibcxx_requires_can_decrement_range(__first, __last, __result);
 
       return std::__copy_move_backward_a2<true>(std::__miter_base(__first),
 						std::__miter_base(__last),
diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h
index bddaa1c..f157a6d 100644
--- a/libstdc++-v3/include/debug/debug.h
+++ b/libstdc++-v3/include/debug/debug.h
@@ -63,6 +63,8 @@  namespace __gnu_debug
 # define __glibcxx_requires_cond(_Cond,_Msg)
 # define __glibcxx_requires_valid_range(_First,_Last)
 # 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)
 # define __glibcxx_requires_sorted(_First,_Last)
 # define __glibcxx_requires_sorted_pred(_First,_Last,_Pred)
 # define __glibcxx_requires_sorted_set(_First1,_Last1,_First2)
@@ -89,6 +91,10 @@  namespace __gnu_debug
   __glibcxx_check_valid_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)	\
+  __glibcxx_check_can_increment_range(_First1,_Last1,_First2)
+# define __glibcxx_requires_can_decrement_range(_First1,_Last1,_First2)	\
+  __glibcxx_check_can_decrement_range(_First1,_Last1,_First2)
 # define __glibcxx_requires_sorted(_First,_Last)	\
   __glibcxx_check_sorted(_First,_Last)
 # define __glibcxx_requires_sorted_pred(_First,_Last,_Pred)	\
diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
index 3a8cbe8..44f48b0 100644
--- a/libstdc++-v3/include/debug/macros.h
+++ b/libstdc++-v3/include/debug/macros.h
@@ -38,12 +38,15 @@ 
  * the user error and where the error is reported.
  *
  */
+#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func)	\
+  if (! (_Cond))							\
+    __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)		\
+      ._ErrMsg._M_error()
+
 #define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func)	\
   do									\
   {									\
-    if (! (_Cond))							\
-      __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)		\
-	._ErrMsg._M_error();						\
+    _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func);	\
   } while (false)
 
 #define _GLIBCXX_DEBUG_VERIFY_AT(_Cond,_ErrMsg,_File,_Line)		\
@@ -91,6 +94,42 @@  _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__can_advance(_First, _Size),	\
 		      ._M_iterator(_First, #_First)			\
 		      ._M_integer(_Size, #_Size))
 
+#define __glibcxx_check_can_increment_range(_First1,_Last1,_First2)	\
+  do									\
+  {									\
+    typename __gnu_debug::_Distance_traits<__decltype(_First1)>::__type __dist;\
+    _GLIBCXX_DEBUG_VERIFY_COND_AT(					\
+			__gnu_debug::__valid_range(_First1, _Last1, __dist),\
+			_M_message(__gnu_debug::__msg_valid_range)	\
+			._M_iterator(_First1, #_First1)			\
+			._M_iterator(_Last1, #_Last1),			\
+			__FILE__,__LINE__,__PRETTY_FUNCTION__);		\
+    _GLIBCXX_DEBUG_VERIFY_COND_AT(					\
+			__gnu_debug::__can_advance(_First2, __dist.first),\
+			_M_message(__gnu_debug::__msg_iter_subscript_oob)\
+			._M_iterator(_First2, #_First2)			\
+			._M_integer(__dist.first),			\
+			__FILE__,__LINE__,__PRETTY_FUNCTION__);		\
+  } while(false)
+
+#define __glibcxx_check_can_decrement_range(_First1,_Last1,_First2)	\
+  do									\
+  {									\
+    typename __gnu_debug::_Distance_traits<__decltype(_First1)>::__type __dist;\
+    _GLIBCXX_DEBUG_VERIFY_COND_AT(					\
+			__gnu_debug::__valid_range(_First1, _Last1, __dist),\
+			_M_message(__gnu_debug::__msg_valid_range)	\
+			._M_iterator(_First1, #_First1)			\
+			._M_iterator(_Last1, #_Last1),			\
+			__FILE__,__LINE__,__PRETTY_FUNCTION__);		\
+    _GLIBCXX_DEBUG_VERIFY_COND_AT(					\
+			__gnu_debug::__can_advance(_First2, -__dist.first),\
+			_M_message(__gnu_debug::__msg_iter_subscript_oob)\
+			._M_iterator(_First2, #_First2)			\
+			._M_integer(-__dist.first),			\
+			__FILE__,__LINE__,__PRETTY_FUNCTION__);		\
+  } while(false)
+
 /** Verify that we can insert into *this with the iterator _Position.
  *  Insertion into a container at a specific position requires that
  *  the iterator be nonsingular, either dereferenceable or past-the-end,
@@ -152,7 +191,7 @@  _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__foreign_iterator(_Position,_First,_Last),\
  *  _Safe_sequence and the _Position iterator is a _Safe_iterator.
 */
 #define __glibcxx_check_insert_range_after(_Position,_First,_Last,_Dist)\
-  __glibcxx_check_valid_range2(_First,_Last,_Dist);			\
+__glibcxx_check_valid_range2(_First,_Last,_Dist);			\
 __glibcxx_check_insert_after(_Position);				\
 _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__foreign_iterator(_Position,_First,_Last),\
 		      _M_message(__gnu_debug::__msg_insert_range_from_self)\
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/1_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/1_neg.cc
new file mode 100644
index 0000000..10375b7
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/1_neg.cc
@@ -0,0 +1,37 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <vector>
+
+void
+test01()
+{
+  std::vector<int> vect;
+  vect.push_back(1);
+  std::copy_backward(vect.end(), vect.begin(), vect.end());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/2_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/2_neg.cc
new file mode 100644
index 0000000..7f6bcd1
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/2_neg.cc
@@ -0,0 +1,37 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <vector>
+
+void
+test01()
+{
+  std::vector<int> vect;
+  vect.push_back(1);
+  std::copy_backward(vect.begin(), vect.end(), vect.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/3_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/3_neg.cc
new file mode 100644
index 0000000..89d5d0a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/3_neg.cc
@@ -0,0 +1,41 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <list>
+
+void
+test01()
+{
+  std::list<int> l1, l2;
+  l1.push_back(1);
+  l1.push_back(2);
+  l1.push_back(3);
+
+  l2.push_back(1);
+  std::copy_backward(++l1.begin(), l1.end(), l2.end());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/debug/1_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/debug/1_neg.cc
new file mode 100644
index 0000000..096c785e
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/debug/1_neg.cc
@@ -0,0 +1,37 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <vector>
+
+void
+test01()
+{
+  std::vector<int> vect;
+  vect.push_back(1);
+  std::equal(vect.end(), vect.begin(), vect.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/debug/2_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/debug/2_neg.cc
new file mode 100644
index 0000000..97b1e1f
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/debug/2_neg.cc
@@ -0,0 +1,37 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <vector>
+
+void
+test01()
+{
+  std::vector<int> v1, v2;
+  v1.push_back(1);
+  std::equal(v1.begin(), v1.end(), v2.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/debug/3_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/debug/3_neg.cc
new file mode 100644
index 0000000..48bcea7
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/debug/3_neg.cc
@@ -0,0 +1,43 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <algorithm>
+#include <list>
+
+void
+test01()
+{
+  std::list<int> l1, l2;
+  l1.push_back(1);
+  l1.push_back(2);
+  l1.push_back(3);
+
+  l2.push_back(1);
+  l2.push_back(2);
+
+  std::equal(++l1.begin(), l1.end(), ++l2.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}