This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [RFA] Adding n <= max_size check in allocator::allocate
- From: Paolo Carlini <pcarlini at suse dot de>
- To: Paolo Carlini <pcarlini at suse dot de>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Wed, 20 Oct 2004 16:43:01 +0200
- Subject: Re: [RFA] Adding n <= max_size check in allocator::allocate
- References: <4175ADDB.3080501@suse.de>
Paolo Carlini wrote:
From a QoI point of view, at least, I think we should have these
checks in our allocators (only pool_allocator is ok!) and mean to
work on this ASAP, together with the corresponding testcases.
Hi again,
Just finished testing the below on x86/x86_64,
--enable-libstdcxx-allocator=mt,
bitmap, new, pool.
I will commit it later today, barring objections...
Paolo.
///////////////
2004-10-20 Paolo Carlini <pcarlini@suse.de>
* include/ext/bitmap_allocator.h (allocate): Throw std::bad_alloc
when n > max_size().
* include/ext/malloc_allocator.h (allocate): Likewise.
* include/ext/mt_allocator.h (allocate): Likewise.
* include/ext/new_allocator.h (allocate): Likewise.
* include/ext/array_allocator.h (allocate): Tweak a bit the
bad_alloc test.
* include/ext/pool_allocator.h: Use __builtin_expect.
* testsuite/ext/array_allocator/check_allocate_too_big.cc: New.
* testsuite/ext/bitmap_allocator/check_allocate_too_big.cc: Likewise.
* testsuite/ext/malloc_allocator/check_allocate_too_big.cc: Likewise.
* testsuite/ext/mt_allocator/check_allocate_too_big.cc: Likewise.
* testsuite/ext/new_allocator/check_allocate_too_big.cc: Likewise.
* testsuite/ext/pool_allocator/check_allocate_too_big.cc: Likewise.
* testsuite/testsuite_allocator.h (check_allocate_too_big): New test.
diff -urN libstdc++-v3-orig/include/ext/array_allocator.h libstdc++-v3/include/ext/array_allocator.h
--- libstdc++-v3-orig/include/ext/array_allocator.h 2004-10-15 01:03:23.000000000 +0200
+++ libstdc++-v3/include/ext/array_allocator.h 2004-10-20 14:06:27.000000000 +0200
@@ -31,6 +31,7 @@
#define _ARRAY_ALLOCATOR_H 1
#include <cstddef>
+#include <bits/functexcept.h>
#include <new>
#include <tr1/array>
@@ -117,8 +118,9 @@
allocate(size_type __n, const void* = 0)
{
static size_type __used;
- if (__builtin_expect(__used + __n > array_type::_S_index, false))
- throw std::bad_alloc();
+ if (__builtin_expect(size_type(array_type::_S_index) - __used < __n,
+ false))
+ std::__throw_bad_alloc();
pointer __ret = _M_array->begin() + __used;
__used += __n;
return __ret;
diff -urN libstdc++-v3-orig/include/ext/bitmap_allocator.h libstdc++-v3/include/ext/bitmap_allocator.h
--- libstdc++-v3-orig/include/ext/bitmap_allocator.h 2004-10-17 16:46:29.000000000 +0200
+++ libstdc++-v3/include/ext/bitmap_allocator.h 2004-10-20 13:19:59.000000000 +0200
@@ -38,6 +38,9 @@
// For std::size_t, and ptrdiff_t.
#include <cstddef>
+// For __throw_bad_alloc().
+#include <bits/functexcept.h>
+
// For std::pair.
#include <utility>
@@ -1084,13 +1087,18 @@
pointer
allocate(size_type __n)
{
- if (__builtin_expect(__n == 1, true))
- return this->_M_allocate_single_object();
- else
- {
- const size_type __b = __n * sizeof(value_type);
- return reinterpret_cast<pointer>(::operator new(__b));
+ if (__builtin_expect(__n <= this->max_size(), true))
+ {
+ if (__builtin_expect(__n == 1, true))
+ return this->_M_allocate_single_object();
+ else
+ {
+ const size_type __b = __n * sizeof(value_type);
+ return reinterpret_cast<pointer>(::operator new(__b));
+ }
}
+ else
+ std::__throw_bad_alloc();
}
pointer
@@ -1119,7 +1127,7 @@
size_type
max_size() const throw()
- { return (size_type()-1)/sizeof(value_type); }
+ { return size_type(-1) / sizeof(value_type); }
void
construct(pointer __p, const_reference __data)
diff -urN libstdc++-v3-orig/include/ext/malloc_allocator.h libstdc++-v3/include/ext/malloc_allocator.h
--- libstdc++-v3-orig/include/ext/malloc_allocator.h 2004-03-24 22:40:01.000000000 +0100
+++ libstdc++-v3/include/ext/malloc_allocator.h 2004-10-20 13:16:17.000000000 +0200
@@ -31,6 +31,7 @@
#define _MALLOC_ALLOCATOR_H 1
#include <new>
+#include <bits/functexcept.h>
namespace __gnu_cxx
{
@@ -79,10 +80,15 @@
pointer
allocate(size_type __n, const void* = 0)
{
- pointer __ret = static_cast<_Tp*>(malloc(__n * sizeof(_Tp)));
- if (!__ret)
- throw std::bad_alloc();
- return __ret;
+ if (__builtin_expect(__n <= this->max_size(), true))
+ {
+ pointer __ret = static_cast<_Tp*>(malloc(__n * sizeof(_Tp)));
+ if (!__ret)
+ std::__throw_bad_alloc();
+ return __ret;
+ }
+ else
+ std::__throw_bad_alloc();
}
// __p is not permitted to be a null pointer.
diff -urN libstdc++-v3-orig/include/ext/mt_allocator.h libstdc++-v3/include/ext/mt_allocator.h
--- libstdc++-v3-orig/include/ext/mt_allocator.h 2004-10-17 17:22:02.000000000 +0200
+++ libstdc++-v3/include/ext/mt_allocator.h 2004-10-20 13:15:41.000000000 +0200
@@ -685,41 +685,46 @@
{
this->_S_initialize_once();
- // Requests larger than _M_max_bytes are handled by operator
- // new/delete directly.
- __pool_type& __pool = this->_S_get_pool();
- const size_t __bytes = __n * sizeof(_Tp);
- if (__pool._M_check_threshold(__bytes))
+ if (__builtin_expect(__n <= this->max_size(), true))
{
- void* __ret = ::operator new(__bytes);
- return static_cast<_Tp*>(__ret);
- }
-
- // Round up to power of 2 and figure out which bin to use.
- const size_t __which = __pool._M_get_binmap(__bytes);
- const size_t __thread_id = __pool._M_get_thread_id();
-
- // Find out if we have blocks on our freelist. If so, go ahead
- // and use them directly without having to lock anything.
- char* __c;
- typedef typename __pool_type::_Bin_record _Bin_record;
- const _Bin_record& __bin = __pool._M_get_bin(__which);
- if (__bin._M_first[__thread_id])
- {
- // Already reserved.
- typedef typename __pool_type::_Block_record _Block_record;
- _Block_record* __block = __bin._M_first[__thread_id];
- __bin._M_first[__thread_id] = __block->_M_next;
+ // Requests larger than _M_max_bytes are handled by operator
+ // new/delete directly.
+ __pool_type& __pool = this->_S_get_pool();
+ const size_t __bytes = __n * sizeof(_Tp);
+ if (__pool._M_check_threshold(__bytes))
+ {
+ void* __ret = ::operator new(__bytes);
+ return static_cast<_Tp*>(__ret);
+ }
+
+ // Round up to power of 2 and figure out which bin to use.
+ const size_t __which = __pool._M_get_binmap(__bytes);
+ const size_t __thread_id = __pool._M_get_thread_id();
- __pool._M_adjust_freelist(__bin, __block, __thread_id);
- __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
+ // Find out if we have blocks on our freelist. If so, go ahead
+ // and use them directly without having to lock anything.
+ char* __c;
+ typedef typename __pool_type::_Bin_record _Bin_record;
+ const _Bin_record& __bin = __pool._M_get_bin(__which);
+ if (__bin._M_first[__thread_id])
+ {
+ // Already reserved.
+ typedef typename __pool_type::_Block_record _Block_record;
+ _Block_record* __block = __bin._M_first[__thread_id];
+ __bin._M_first[__thread_id] = __block->_M_next;
+
+ __pool._M_adjust_freelist(__bin, __block, __thread_id);
+ __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
+ }
+ else
+ {
+ // Null, reserve.
+ __c = __pool._M_reserve_block(__bytes, __thread_id);
+ }
+ return static_cast<_Tp*>(static_cast<void*>(__c));
}
else
- {
- // Null, reserve.
- __c = __pool._M_reserve_block(__bytes, __thread_id);
- }
- return static_cast<_Tp*>(static_cast<void*>(__c));
+ std::__throw_bad_alloc();
}
template<typename _Tp, typename _Poolp>
diff -urN libstdc++-v3-orig/include/ext/new_allocator.h libstdc++-v3/include/ext/new_allocator.h
--- libstdc++-v3-orig/include/ext/new_allocator.h 2004-02-23 16:41:43.000000000 +0100
+++ libstdc++-v3/include/ext/new_allocator.h 2004-10-20 13:26:48.000000000 +0200
@@ -31,6 +31,7 @@
#define _NEW_ALLOCATOR_H 1
#include <new>
+#include <bits/functexcept.h>
namespace __gnu_cxx
{
@@ -78,7 +79,12 @@
// about what the return value is when __n == 0.
pointer
allocate(size_type __n, const void* = 0)
- { return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }
+ {
+ if (__builtin_expect(__n <= this->max_size(), true))
+ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
+ else
+ std::__throw_bad_alloc();
+ }
// __p is not permitted to be a null pointer.
void
diff -urN libstdc++-v3-orig/include/ext/pool_allocator.h libstdc++-v3/include/ext/pool_allocator.h
--- libstdc++-v3-orig/include/ext/pool_allocator.h 2004-10-15 01:03:24.000000000 +0200
+++ libstdc++-v3/include/ext/pool_allocator.h 2004-10-20 13:26:08.000000000 +0200
@@ -189,9 +189,9 @@
__pool_alloc<_Tp>::allocate(size_type __n, const void*)
{
pointer __ret = 0;
- if (__n)
+ if (__builtin_expect(__n != 0, true))
{
- if (__n <= max_size())
+ if (__builtin_expect(__n <= this->max_size(), true))
{
// If there is a race through here, assume answer from getenv
// will resolve in same direction. Inspired by techniques
@@ -234,7 +234,7 @@
void
__pool_alloc<_Tp>::deallocate(pointer __p, size_type __n)
{
- if (__n && (__p != 0))
+ if (__builtin_expect(__n != 0 && __p != 0, true))
{
const size_t __bytes = __n * sizeof(_Tp);
if (__bytes > static_cast<size_t>(_S_max_bytes) || _S_force_new == 1)
diff -urN libstdc++-v3-orig/testsuite/ext/array_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/array_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/array_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/array_allocator/check_allocate_too_big.cc 2004-10-20 13:55:05.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/array_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::array_allocator<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/ext/bitmap_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/bitmap_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/bitmap_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/bitmap_allocator/check_allocate_too_big.cc 2004-10-20 13:54:29.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/bitmap_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::bitmap_allocator<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/ext/malloc_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/malloc_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/malloc_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/malloc_allocator/check_allocate_too_big.cc 2004-10-20 13:52:08.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/malloc_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::malloc_allocator<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/ext/mt_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/mt_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/mt_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/mt_allocator/check_allocate_too_big.cc 2004-10-20 13:51:45.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/mt_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::__mt_alloc<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/ext/new_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/new_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/new_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/new_allocator/check_allocate_too_big.cc 2004-10-20 13:51:25.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/new_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::new_allocator<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/ext/pool_allocator/check_allocate_too_big.cc libstdc++-v3/testsuite/ext/pool_allocator/check_allocate_too_big.cc
--- libstdc++-v3-orig/testsuite/ext/pool_allocator/check_allocate_too_big.cc 1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/ext/pool_allocator/check_allocate_too_big.cc 2004-10-20 13:51:05.000000000 +0200
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2004 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 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 COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 20.4.1.1 allocator members
+
+#include <ext/pool_allocator.h>
+#include <testsuite_allocator.h>
+
+int main()
+{
+ typedef int value_type;
+ typedef __gnu_cxx::__pool_alloc<value_type> allocator_type;
+ __gnu_test::check_allocate_too_big<allocator_type>();
+ return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/testsuite_allocator.h libstdc++-v3/testsuite/testsuite_allocator.h
--- libstdc++-v3-orig/testsuite/testsuite_allocator.h 2004-10-15 12:54:57.000000000 +0200
+++ libstdc++-v3/testsuite/testsuite_allocator.h 2004-10-20 13:50:32.000000000 +0200
@@ -36,6 +36,7 @@
#define _GLIBCXX_TESTSUITE_ALLOCATOR_H
#include <cstddef>
+#include <cstdlib>
#include <limits>
namespace
@@ -205,7 +206,27 @@
a.deallocate(NULL, 1);
a.deallocate(NULL, 10);
}
+
+ template<typename Alloc>
+ bool
+ check_allocate_too_big()
+ {
+ Alloc a;
+ try
+ {
+ a.allocate(a.max_size() + 1);
+ }
+ catch(std::bad_alloc&)
+ {
+ return true;
+ }
+ catch(...)
+ {
+ throw;
+ }
+ throw;
+ }
+
}; // namespace __gnu_test
#endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H
-