This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR 57779 New debug check


Hi

    This is a proposal to add a new debug like proposed in PR 57779.

I fully implemented it that is to say that I also detect when trying to self insert pointers to the std::vector rather than iterators.

I had to introduce a __is_lvalue_reference, should I add it to bits/cpp_type_traits.h or is there another way to access it without the C++11 mode ?

    Tested under linux x86_64.

2013-07-10  François Dumont  <fdumont@gcc.gnu.org>

    PR libstdc++/57779
    * include/debug/formatter.h (_Debug_msg_id): Add
    __msg_insert_itself_range entry.
    * include/debug/functions.h (__foreign_iterator): New function
    checking if an iterator points to a given sequence.
    * include/debug/macros.h (__glibcxx_check_insert_range): Add check
    using __foreign_iterator.
    * src/c++11/debug.cc (_S_debug_messages): Add
    __msg_insert_itself_range_entry message.
    (_Error_formatter::_Parameter::_M_print_description): Display
    iterator sequence address rather than sequence address when the
    parameter type is an iterator.
    (_Error_formatter::_M_print_word): Enhance behavior when
    displaying a word with an appended '\n'.
    * testsuite/util/debug/checks.h (check_insert4): New.
    * testsuite/23_containers/deque/debug/insert5_neg.cc: New.
    * testsuite/23_containers/vector/debug/insert5_neg.cc: Likewise.
    * testsuite/23_containers/vector/debug/insert6_neg.cc: Likewise.
    * testsuite/23_containers/vector/debug/57779_neg.cc: Likewise.

François

Index: include/debug/macros.h
===================================================================
--- include/debug/macros.h	(revision 200882)
+++ include/debug/macros.h	(working copy)
@@ -101,15 +101,16 @@
  *  that it reference the sequence we are inserting into, and that the
  *  iterator range [_First, Last) is a valid (possibly empty)
  *  range. Note that this macro is only valid when the container is a
- *  _Safe_sequence and the iterator is a _Safe_iterator.
- *
- *  @todo We would like to be able to check for noninterference of
- *  _Position and the range [_First, _Last), but that can't (in
- *  general) be done.
+ *  _Safe_sequence and the _Position iterator is a _Safe_iterator.
 */
 #define __glibcxx_check_insert_range(_Position,_First,_Last)		\
 __glibcxx_check_valid_range(_First,_Last);				\
-__glibcxx_check_insert(_Position)
+__glibcxx_check_insert(_Position);					\
+_GLIBCXX_DEBUG_VERIFY(__gnu_debug::__foreign_iterator(_Position,_First),\
+		      _M_message(__gnu_debug::__msg_insert_itself_range)\
+		      ._M_iterator(_First, #_First)			\
+		      ._M_iterator(_Last, #_Last)			\
+		      ._M_sequence(*this, "this"))
 
 /** Verify that we can insert the values in the iterator range
  *  [_First, _Last) into *this after the iterator _Position.  Insertion
Index: include/debug/formatter.h
===================================================================
--- include/debug/formatter.h	(revision 200882)
+++ include/debug/formatter.h	(working copy)
@@ -114,7 +114,9 @@
     // unordered container buckets
     __msg_bucket_index_oob,
     __msg_valid_load_factor,
-    __msg_equal_allocs
+    // others
+    __msg_equal_allocs,
+    __msg_insert_itself_range
   };
 
   class _Error_formatter
Index: include/debug/functions.h
===================================================================
--- include/debug/functions.h	(revision 200882)
+++ include/debug/functions.h	(working copy)
@@ -162,6 +162,105 @@
       return __first;
     }
 
+  template<typename>
+    struct __is_lvalue_reference : std::__false_type
+    { };
+
+  template<typename _Tp>
+    struct __is_lvalue_reference<_Tp&> : std::__true_type
+    { };
+
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    _InputIterator __other,
+			    std::__true_type)
+    {
+      // Only containers having all elements in continuous memory can have its
+      // elements passed through pointers.
+      if (&(*(__it._M_get_sequence()->_M_base().end()))
+	  - &(*(__it._M_get_sequence()->_M_base().begin()))
+	  == __it._M_get_sequence()->size())
+	return &(*__other) < &(*(__it._M_get_sequence()->_M_base().begin()))
+	  || &(*__other) >= &(*(__it._M_get_sequence()->_M_base().end()));
+
+      return true;
+    }
+			   
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    _InputIterator __other,
+			    std::__false_type)
+    {
+      // Simply can't say so consider it is fine.
+      return true;
+    }
+			   
+  /* Checks that an iterator do not belong to the same sequence that the one of
+   * a reference iterator.
+  */
+  template<typename _Iterator, typename _Sequence, typename _OtherIterator>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
+		const _Safe_iterator<_OtherIterator, _Sequence>& __other,
+		std::random_access_iterator_tag)
+    { return __it._M_get_sequence() != __other._M_get_sequence(); }
+			   
+  /* This overload detect when passing pointers to the contained elements rather
+     than using iterators.
+   */
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			    _InputIterator __other,
+			    std::random_access_iterator_tag)
+    {
+      typedef typename _Sequence::const_iterator _ItType;
+      typedef typename std::iterator_traits<_ItType>::reference _Ref;
+      return __foreign_iterator_aux3(__it, __other,
+				     __is_lvalue_reference<_Ref>());
+    }
+			   
+  /* For node based container, having not random access iterators,
+   * implementation supports usage of not foreign iterator.
+   */
+  template<typename _Iterator, typename _Sequence, typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>&,
+			   _InputIterator,
+			   std::input_iterator_tag)
+    { return true; }
+			   
+  template<typename _Iterator, typename _Sequence,
+	   typename _Integral>
+    inline bool
+    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			   _Integral __other,
+			   std::__true_type)
+    { return true; }
+
+  template<typename _Iterator, typename _Sequence,
+	   typename _InputIterator>
+    inline bool
+    __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>& __it,
+			   _InputIterator __other,
+			   std::__false_type)
+    {
+      return __foreign_iterator_aux2(__it, __other,
+				     std::__iterator_category(__it));
+    }
+
+  template<typename _Iterator, typename _Sequence,
+	   typename _InputIterator>
+    inline bool
+    __foreign_iterator(const _Safe_iterator<_Iterator, _Sequence>& __it,
+		       _InputIterator __other)
+    {
+      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+      return __foreign_iterator_aux(__it, __other, _Integral());
+    }
+
   /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
   template<typename _CharT, typename _Integer>
     inline const _CharT*
Index: testsuite/23_containers/deque/debug/insert5_neg.cc
===================================================================
--- testsuite/23_containers/deque/debug/insert5_neg.cc	(revision 0)
+++ testsuite/23_containers/deque/debug/insert5_neg.cc	(revision 0)
@@ -0,0 +1,33 @@
+// Copyright (C) 2013 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-require-debug-mode "" }
+// { dg-do run { xfail *-*-* } }
+
+#include <deque>
+#include <debug/checks.h>
+
+void test01()
+{
+  __gnu_test::check_insert4<std::deque<int> >();
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
Index: testsuite/23_containers/vector/debug/insert5_neg.cc
===================================================================
--- testsuite/23_containers/vector/debug/insert5_neg.cc	(revision 0)
+++ testsuite/23_containers/vector/debug/insert5_neg.cc	(revision 0)
@@ -0,0 +1,33 @@
+// Copyright (C) 2013 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-require-debug-mode "" }
+// { dg-do run { xfail *-*-* } }
+
+#include <vector>
+#include <debug/checks.h>
+
+void test01()
+{
+  __gnu_test::check_insert4<std::vector<int> >();
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
Index: testsuite/23_containers/vector/debug/insert6_neg.cc
===================================================================
--- testsuite/23_containers/vector/debug/insert6_neg.cc	(revision 0)
+++ testsuite/23_containers/vector/debug/insert6_neg.cc	(revision 0)
@@ -0,0 +1,48 @@
+// Copyright (C) 2013 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-require-debug-mode "" }
+// { dg-do run { xfail *-*-* } }
+
+#include <debug/vector>
+#include <debug/checks.h>
+
+void test01()
+{
+  std::vector<bool> v;
+  __gnu_debug::vector<bool> dv;
+  for (int i = 0; i != 10; ++i)
+    {
+      v.push_back((i % 2) != 0);
+      dv.push_back((i % 2) == 0);
+    }
+
+  dv.insert(dv.begin(), v.begin(), v.begin() + 5);
+  VERIFY( dv.size() == 15 );
+}
+
+void test02()
+{
+  __gnu_test::check_insert4<__gnu_debug::vector<bool> >();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/vector/debug/57779_neg.cc
===================================================================
--- testsuite/23_containers/vector/debug/57779_neg.cc	(revision 0)
+++ testsuite/23_containers/vector/debug/57779_neg.cc	(revision 0)
@@ -0,0 +1,37 @@
+// Copyright (C) 2013 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-require-debug-mode "" }
+// { dg-do run { xfail *-*-* } }
+
+#include <vector>
+#include <debug/checks.h>
+
+void test01()
+{
+  std::vector<int> v;
+  for (int i = 0; i != 10; ++i)
+    v.push_back(i);
+
+  v.insert(v.begin(), v.data() + 1, v.data() + 5); // Expected failure
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
Index: testsuite/util/debug/checks.h
===================================================================
--- testsuite/util/debug/checks.h	(revision 200882)
+++ testsuite/util/debug/checks.h	(working copy)
@@ -129,7 +129,7 @@
       c2.assign(last, first); // Expected failure
     }
 
-  // Check that invalid range of debug !random debug iterators is detected
+  // Check that invalid range of debug not random iterators is detected
   template<typename _Tp>
     void
     check_assign3()
@@ -377,6 +377,34 @@
     }
 
   template<typename _Tp>
+    void
+    check_insert4()
+    {
+      bool test __attribute__((unused)) = true;
+
+      typedef _Tp cont_type;
+      typedef typename cont_type::value_type cont_val_type;
+      typedef typename CopyableValueType<cont_val_type>::value_type val_type;
+      typedef std::list<val_type> list_type;
+
+      generate_unique<val_type> gu;
+
+      list_type l;
+      for (int i = 0; i != 5; ++i)
+        l.push_back(gu.build());
+      VERIFY(l.size() == 5);
+
+      typename list_type::iterator first = l.begin(); ++first;
+      typename list_type::iterator last = first; ++last; ++last;
+
+      cont_type c1;
+      InsertRangeHelper<cont_type>::Insert(c1, l.begin(), l.end());
+      VERIFY(c1.size() == 5);
+
+      c1.insert(c1.begin(), c1.begin(), c1.end()); // Expected failure.
+    }
+
+  template<typename _Tp>
     void use_invalid_iterator()
     {
       bool test __attribute__((unused)) = true;
Index: src/c++11/debug.cc
===================================================================
--- src/c++11/debug.cc	(revision 200882)
+++ src/c++11/debug.cc	(working copy)
@@ -181,7 +181,8 @@
     "attempt to access container with out-of-bounds bucket index %2;,"
     " container only holds %3; buckets",
     "load factor shall be positive",
-    "allocators must be equal"
+    "allocators must be equal",
+    "attempt to insert with an iterator range [%1.name;, %2.name;) from this container"
   };
 
   void
@@ -695,7 +696,7 @@
 	      }
 	    
 	    __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", 
-					_M_variant._M_sequence._M_address);
+					_M_variant._M_iterator._M_sequence);
 	    __formatter->_M_print_word(__buf);
 	  }
 	__formatter->_M_print_word("}\n");
@@ -808,8 +809,11 @@
     if (__length == 0)
       return;
     
-    if ((_M_column + __length < _M_max_length)
-	|| (__length >= _M_max_length && _M_column == 1)) 
+    size_t __visual_length
+      = __word[__length - 1] == '\n' ? __length - 1 : __length;
+    if (__visual_length == 0
+	|| (_M_column + __visual_length < _M_max_length)
+	|| (__visual_length >= _M_max_length && _M_column == 1)) 
       {
 	// If this isn't the first line, indent
 	if (_M_column == 1 && !_M_first_line)
@@ -823,17 +827,17 @@
 	  }
 	
 	fprintf(stderr, "%s", __word);
-	_M_column += __length;
 	
 	if (__word[__length - 1] == '\n') 
 	  {
 	    _M_first_line = false;
 	    _M_column = 1;
 	  }
+	else
+	  _M_column += __length;
       }
     else
       {
-	_M_column = 1;
 	_M_print_word("\n");
 	_M_print_word(__word);
       }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]