This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
PR 57779 New debug check
- From: François Dumont <frs dot dumont at gmail dot com>
- To: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Date: Wed, 10 Jul 2013 22:31:28 +0200
- Subject: 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);
}