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]

Re: [RFA] Adding n <= max_size check in allocator::allocate


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
-

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