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]

[Patch] libstdc++/25288


Hi,

the below is what I have for the issue: see 23.2.2.3/1. Probably,
resolving libstdc++/21772 will obsolete the basic testing allocator
provided by submitter, but for the time being seems sufficient for the job.

Anyway, looks fine to everyone? Anything simpler? Otherwise I will go
ahead for mainline. After a bit of testing seems suited also for 4_1-branch.

Paolo.

///////////////////
2005-12-09  Paolo Carlini  <pcarlini@suse.de>

	PR libstdc++/25288
	* include/bits/stl_list.h (list<>::_M_insert_dispatch(__false_type),
	_M_fill_insert): If _M_create_node throws, erase the elements just
	inserted.
	* testsuite/23_containers/list/modifiers/insert/25288.cc: New.
	* testsuite/testsuite_allocator.h (class throw_allocator): Add.
Index: include/bits/stl_list.h
===================================================================
--- include/bits/stl_list.h	(revision 108226)
+++ include/bits/stl_list.h	(working copy)
@@ -1113,8 +1113,23 @@
 			   _InputIterator __first, _InputIterator __last,
 			   __false_type)
         {
-	  for (; __first != __last; ++__first)
-	    _M_insert(__pos, *__first);
+	  iterator __tmp(__pos);
+	  try
+	    {
+	      if (__first != __last)
+		{
+		  __tmp = insert(__pos, *__first);
+		  ++__first;
+		}
+
+	      for (; __first != __last; ++__first)
+		_M_insert(__pos, *__first);
+	    }
+	  catch(...)
+	    {
+	      erase(__tmp, __pos);
+	      __throw_exception_again;
+	    }      
 	}
 
       // Called by insert(p,n,x), and the range insert when it turns out
@@ -1122,8 +1137,23 @@
       void
       _M_fill_insert(iterator __pos, size_type __n, const value_type& __x)
       {
-	for (; __n > 0; --__n)
-	  _M_insert(__pos, __x);
+	iterator __tmp(__pos);
+	try
+	  {
+	    if (__n)
+	      {
+		__tmp = insert(__pos, __x);
+		--__n;
+	      }
+
+	    for (; __n > 0; --__n)
+	      _M_insert(__pos, __x);
+	  }
+	catch(...)
+	  {
+	    erase(__tmp, __pos);
+	    __throw_exception_again;
+	  }
       }
 
 
Index: testsuite/23_containers/list/modifiers/insert/25288.cc
===================================================================
--- testsuite/23_containers/list/modifiers/insert/25288.cc	(revision 0)
+++ testsuite/23_containers/list/modifiers/insert/25288.cc	(revision 0)
@@ -0,0 +1,92 @@
+// Copyright (C) 2005 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.2.3 list modifiers [lib.list.modifiers]
+
+#include <list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+// libstdc++/25288
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef __gnu_test::throw_allocator<int> my_alloc;
+  typedef std::list<int, my_alloc > my_list;
+
+  for (int j = 0; j < 10; ++j)
+    for (int i = 0; i < 10; ++i)
+      {
+	my_alloc alloc1(j + i);
+	my_list list1(alloc1);
+	
+	for (int k = 0; k < j; ++k)
+	  list1.push_back(-(k + 1));
+      
+	try
+	  {
+	    list1.insert(list1.begin(), 10, 99);
+	    VERIFY( false );
+	  }
+	catch (std::bad_alloc&)
+	  {
+	    VERIFY( true );
+	  }
+	catch (...)
+	  {
+	    VERIFY( false );
+	  }
+	
+	VERIFY( list1.size() == my_list::size_type(j) );
+	VERIFY( list1.size() == 0 || list1.back() == -j );
+	VERIFY( list1.size() == 0 || list1.front() == -1 );
+
+	my_alloc alloc2(j + i);
+	my_list list2(alloc2);
+	
+	const int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+	
+	for (int k = 0; k < j; ++k)
+	  list2.push_back(-(k + 1));
+	
+	try
+	  {
+	    list2.insert(list2.begin(), data, data + 10);
+	    VERIFY( false );
+	  }
+	catch (std::bad_alloc&)
+	  {
+	    VERIFY( true );
+	  }
+	catch (...)
+	  {
+	    VERIFY( false );
+	  }
+
+	VERIFY( list2.size() == my_list::size_type(j) );
+	VERIFY( list2.size() == 0 || list2.back() == -j );
+	VERIFY( list2.size() == 0 || list2.front() == -1 );
+      }
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
Index: testsuite/testsuite_allocator.h
===================================================================
--- testsuite/testsuite_allocator.h	(revision 108226)
+++ testsuite/testsuite_allocator.h	(working copy)
@@ -1,7 +1,7 @@
 // -*- C++ -*-
 // Testing allocator for the C++ library testsuite.
 //
-// Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+// Copyright (C) 2002, 2003, 2004, 2005 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
@@ -229,6 +229,81 @@
 	}
       throw;
     }
+
+  template<typename Tp>
+    class throw_allocator
+    {
+    public:
+      typedef std::size_t                         size_type;
+      typedef std::ptrdiff_t                      difference_type;
+      typedef Tp*                                 pointer;
+      typedef const Tp*                           const_pointer;
+      typedef Tp&                                 reference;
+      typedef const Tp&                           const_reference;
+      typedef Tp                                  value_type;
+      
+      template<typename Tp1>
+        struct rebind
+	{ typedef throw_allocator<Tp1> other; };
+
+      throw_allocator() throw()
+      : count(size_type(-1)) { }
+
+      throw_allocator(size_type c) throw()
+      : count(c) { }
+      
+      template<typename Tp1>
+        throw_allocator(const throw_allocator<Tp1>& b) throw()
+	: count(b.get_count()) { }
+
+      size_type get_count() const { return count; }
+      
+      pointer
+      address(reference x) const { return &x; }
+    
+      const_pointer
+      address(const_reference x) const { return &x; }
+    
+      pointer
+      allocate(size_type n, const void* = 0)
+      {
+        if (count == 0)
+	  throw std::bad_alloc();
+	
+	if (count != size_type(-1))
+	  --count;
+        
+	return static_cast<Tp*>(::operator new(n * sizeof(Tp)));
+      }
+      
+      void
+      deallocate(pointer p, size_type)
+      { ::operator delete(p); }
+      
+      size_type
+      max_size() const throw() 
+      { return size_type(-1) / sizeof(Tp); }
+      
+      void 
+      construct(pointer p, const Tp& val) 
+      { ::new(p) Tp(val); }
+    
+      void 
+      destroy(pointer p) { p->~Tp(); }
+
+    private:
+      template<typename Tp1>
+        friend inline bool
+        operator==(const throw_allocator&, const throw_allocator<Tp1>&)
+        { return true; }
+
+      template<typename Tp1>
+        friend inline bool
+        operator!=(const throw_allocator&, const throw_allocator<Tp1>&)
+        { return false; }
+      
+      size_type count;
+    };
 }; // 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]