This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[Patch] libstdc++/31370
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Cc: gcc at severeweblint dot org
- Date: Sun, 01 Apr 2007 18:12:23 +0200
- Subject: [Patch] libstdc++/31370
Hi,
the below is what I have for this PR: basically I took the patch
provided by Matthew and commonized the checks to a single _M_check_len.
The same I could do for the primary template, a nice clean-up.
I was afraid the testcase could stress too much the memory management of
some machines, but apparently I have no problems running it on various
x86 and x86-64 linux machines and also a few non-linux machines. Thus I
mean to add it too, for now.
Paolo.
///////////////////
2007-04-02 Matthew Levine <gcc@severeweblint.org>
Paolo Carlini <pcarlini@suse.de>
PR libstdc++/31370
* include/bits/stl_bvector.h (vector<bool>::max_size): Fix.
(vector<bool>::_M_check_len): Add.
* include/bits/vector.tcc (_M_fill_insert(iterator, size_type, bool),
_M_insert_range(iterator, _ForwardIterator, _ForwardIterator,
std::forward_iterator_tag), _M_insert_aux(iterator, bool)): Use it.
* testsuite/23_containers/vector/bool/modifiers/insert/31370.cc: New.
* testsuite/23_containers/vector/bool/capacity/29134.cc: Adjust.
* include/bits/stl_vector.h (vector<>::_M_check_len): Add.
* include/bits/vector.tcc (_M_insert_aux(iterator, const _Tp&),
_M_fill_insert(iterator, size_type, const value_type&),
_M_range_insert(iterator, _ForwardIterator, _ForwardIterator,
std::forward_iterator_tag)): Use it.
Index: include/bits/stl_vector.h
===================================================================
--- include/bits/stl_vector.h (revision 123388)
+++ include/bits/stl_vector.h (working copy)
@@ -911,6 +911,17 @@
void
_M_insert_aux(iterator __position, const value_type& __x);
+ // Called by the latter.
+ size_type
+ _M_check_len(size_type __n, const char* __s) const
+ {
+ if (max_size() - size() < __n)
+ __throw_length_error(__N(__s));
+
+ const size_type __len = size() + std::max(size(), __n);
+ return (__len < size() || __len > max_size()) ? max_size() : __len;
+ }
+
// Internal erase functions follow.
// Called by erase(q1,q2), clear(), resize(), _M_fill_assign,
Index: include/bits/vector.tcc
===================================================================
--- include/bits/vector.tcc (revision 123389)
+++ include/bits/vector.tcc (working copy)
@@ -258,17 +258,8 @@
}
else
{
- const size_type __old_size = size();
- if (__old_size == this->max_size())
- __throw_length_error(__N("vector::_M_insert_aux"));
-
- // When sizeof(value_type) == 1 and __old_size > size_type(-1)/2
- // __len overflows: if we don't notice and _M_allocate doesn't
- // throw we crash badly later.
- size_type __len = __old_size != 0 ? 2 * __old_size : 1;
- if (__len < __old_size)
- __len = this->max_size();
-
+ const size_type __len =
+ _M_check_len(size_type(1), "vector::_M_insert_aux");
pointer __new_start(this->_M_allocate(__len));
pointer __new_finish(__new_start);
try
@@ -343,15 +334,8 @@
}
else
{
- const size_type __old_size = size();
- if (this->max_size() - __old_size < __n)
- __throw_length_error(__N("vector::_M_fill_insert"));
-
- // See _M_insert_aux above.
- size_type __len = __old_size + std::max(__old_size, __n);
- if (__len < __old_size)
- __len = this->max_size();
-
+ const size_type __len =
+ _M_check_len(__n, "vector::_M_fill_insert");
pointer __new_start(this->_M_allocate(__len));
pointer __new_finish(__new_start);
try
@@ -447,15 +431,8 @@
}
else
{
- const size_type __old_size = size();
- if (this->max_size() - __old_size < __n)
- __throw_length_error(__N("vector::_M_range_insert"));
-
- // See _M_insert_aux above.
- size_type __len = __old_size + std::max(__old_size, __n);
- if (__len < __old_size)
- __len = this->max_size();
-
+ const size_type __len =
+ _M_check_len(__n, "vector::_M_range_insert");
pointer __new_start(this->_M_allocate(__len));
pointer __new_finish(__new_start);
try
@@ -512,7 +489,8 @@
}
else
{
- const size_type __len = size() + std::max(size(), __n);
+ const size_type __len =
+ _M_check_len(__n, "vector<bool>::_M_fill_insert");
_Bit_type * __q = this->_M_allocate(__len);
iterator __i = _M_copy_aligned(begin(), __position,
iterator(__q, 0));
@@ -547,7 +525,8 @@
}
else
{
- const size_type __len = size() + std::max(size(), __n);
+ const size_type __len =
+ _M_check_len(__n, "vector<bool>::_M_insert_range");
_Bit_type * __q = this->_M_allocate(__len);
iterator __i = _M_copy_aligned(begin(), __position,
iterator(__q, 0));
@@ -577,8 +556,8 @@
}
else
{
- const size_type __len = size() ? 2 * size()
- : static_cast<size_type>(_S_word_bit);
+ const size_type __len =
+ _M_check_len(size_type(1), "vector<bool>::_M_insert_aux");
_Bit_type * __q = this->_M_allocate(__len);
iterator __i = _M_copy_aligned(begin(), __position,
iterator(__q, 0));
Index: include/bits/stl_bvector.h
===================================================================
--- include/bits/stl_bvector.h (revision 123389)
+++ include/bits/stl_bvector.h (working copy)
@@ -582,9 +582,11 @@
size_type
max_size() const
{
+ const size_type __isize =
+ std::numeric_limits<difference_type>::max() - int(_S_word_bit) + 1;
const size_type __asize = _M_get_Bit_allocator().max_size();
- return (__asize <= size_type(-1) / int(_S_word_bit) ?
- __asize * int(_S_word_bit) : size_type(-1));
+ return (__asize <= __isize / int(_S_word_bit)
+ ? __asize * int(_S_word_bit) : __isize);
}
size_type
@@ -922,6 +924,16 @@
void
_M_insert_aux(iterator __position, bool __x);
+ size_type
+ _M_check_len(size_type __n, const char* __s) const
+ {
+ if (max_size() - size() < __n)
+ __throw_length_error(__N(__s));
+
+ const size_type __len = size() + std::max(size(), __n);
+ return (__len < size() || __len > max_size()) ? max_size() : __len;
+ }
+
void
_M_erase_at_end(iterator __pos)
{ this->_M_impl._M_finish = __pos; }
Index: testsuite/23_containers/vector/bool/modifiers/insert/31370.cc
===================================================================
--- testsuite/23_containers/vector/bool/modifiers/insert/31370.cc (revision 0)
+++ testsuite/23_containers/vector/bool/modifiers/insert/31370.cc (revision 0)
@@ -0,0 +1,192 @@
+// Copyright (C) 2007 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 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without Pred 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 COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 23.2.5 class vector<bool> [lib.vector.bool]
+
+// { dg-do run { xfail *-*-darwin8.[0-4].* } }
+
+#include <vector>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+inline void
+check_cap_ge_size(const std::vector<bool>& x)
+{
+ if (x.capacity() < x.size())
+ throw std::logic_error("");
+}
+
+inline void
+check_cap_eq_maxsize(const std::vector<bool>& x)
+{
+ if (x.capacity() != x.max_size())
+ throw std::logic_error("");
+}
+
+// libstdc++/31370
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ int myexit = 0;
+
+ try
+ {
+ std::vector<bool> x;
+ x.reserve(x.max_size());
+ check_cap_eq_maxsize(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ // When doubling is too big, but smaller is sufficient, the resize
+ // should do smaller and be happy. It certainly shouldn't throw
+ // other exceptions or crash.
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() / 2 + 1, false);
+ for(int i = 0; i < std::_S_word_bit; ++i)
+ x.push_back(false);
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() / 2 + 1, false);
+ x.insert(x.end(), std::_S_word_bit, false);
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() / 2 + 1, false);
+ std::vector<bool> y(std::_S_word_bit, false);
+ x.insert(x.end(), y.begin(), y.end());
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ // These tests are currently only relevant to bool: don't get burned
+ // by the attempt to round up when near the max size.
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ for(int i = 0; i < std::_S_word_bit; ++i)
+ x.push_back(false);
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ x.insert(x.end(), std::_S_word_bit, false);
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ std::vector<bool> y(std::_S_word_bit, false);
+ x.insert(x.end(), y.begin(), y.end());
+ check_cap_ge_size(x);
+ }
+ catch(std::bad_alloc&)
+ { }
+ catch(std::exception&)
+ { ++myexit; }
+
+ // Attempts to put in more than max_size() items should result in a
+ // length error.
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ for(int i = 0; i < std::_S_word_bit + 1; ++i)
+ x.push_back(false);
+ ++myexit;
+ }
+ catch(std::bad_alloc)
+ { }
+ catch(std::length_error)
+ { }
+ catch(std::exception)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ x.insert(x.end(), std::_S_word_bit + 1, false);
+ ++myexit;
+ }
+ catch(std::bad_alloc)
+ { }
+ catch(std::length_error)
+ { }
+ catch(std::exception)
+ { ++myexit; }
+
+ try
+ {
+ std::vector<bool> x;
+ x.resize(x.max_size() - std::_S_word_bit, false);
+ std::vector<bool> y(std::_S_word_bit + 1, false);
+ x.insert(x.end(), y.begin(), y.end());
+ ++myexit;
+ }
+ catch(std::bad_alloc)
+ { }
+ catch(std::length_error)
+ { }
+ catch(std::exception)
+ { ++myexit; }
+
+ VERIFY( !myexit );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/23_containers/vector/bool/capacity/29134.cc
===================================================================
--- testsuite/23_containers/vector/bool/capacity/29134.cc (revision 123388)
+++ testsuite/23_containers/vector/bool/capacity/29134.cc (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2006 Free Software Foundation, Inc.
+// Copyright (C) 2006, 2007 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
@@ -28,7 +28,11 @@
std::vector<bool> vb;
- VERIFY( vb.max_size() == std::vector<bool>::size_type(-1) );
+ // Actually, vector<bool> is special, see libstdc++/31370.
+ typedef std::vector<bool>::difference_type difference_type;
+ VERIFY( vb.max_size()
+ == (std::numeric_limits<difference_type>::max()
+ - int(std::_S_word_bit) + 1) );
}
int main()