Author: hhinnant
Date: Fri Jan 11 14:36:59 2013
New Revision: 172250

URL: http://llvm.org/viewvc/llvm-project?rev=172250&view=rev
Log:
Fix exception safety bug in vector::push_back

Added:
    
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
    
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
    
libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
    
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
    
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
    
libcxx/trunk/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
Modified:
    libcxx/trunk/include/memory
    libcxx/trunk/include/vector

Modified: libcxx/trunk/include/memory
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=172250&r1=172249&r2=172250&view=diff
==============================================================================
--- libcxx/trunk/include/memory (original)
+++ libcxx/trunk/include/memory Fri Jan 11 14:36:59 2013
@@ -1571,7 +1571,10 @@
         __construct_backward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, 
_Ptr& __end2)
         {
             while (__end1 != __begin1)
-                construct(__a, _VSTD::__to_raw_pointer(--__end2), 
_VSTD::move_if_noexcept(*--__end1));
+            {
+                construct(__a, _VSTD::__to_raw_pointer(__end2-1), 
_VSTD::move_if_noexcept(*--__end1));
+                --__end2;
+            }
         }
 
     template <class _Tp>

Modified: libcxx/trunk/include/vector
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/vector?rev=172250&r1=172249&r2=172250&view=diff
==============================================================================
--- libcxx/trunk/include/vector (original)
+++ libcxx/trunk/include/vector Fri Jan 11 14:36:59 2013
@@ -1458,7 +1458,8 @@
     allocator_type& __a = this->__alloc();
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), 
size(), __a);
     // __v.push_back(_VSTD::forward<_Up>(__x));
-    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_++), 
_VSTD::forward<_Up>(__x));
+    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), 
_VSTD::forward<_Up>(__x));
+    __v.__end_++;
     __swap_out_circular_buffer(__v);
 }
 
@@ -1505,7 +1506,8 @@
     allocator_type& __a = this->__alloc();
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), 
size(), __a);
 //    __v.emplace_back(_VSTD::forward<_Args>(__args)...);
-    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_++), 
_VSTD::forward<_Args>(__args)...);
+    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), 
_VSTD::forward<_Args>(__args)...);
+    __v.__end_++;
     __swap_out_circular_buffer(__v);
 }
 

Added: 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// void push_back(const value_type& x);
+
+#include <deque>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::deque<CMyClass> vec;
+
+       vec.push_back(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_back(instance);
+       }
+       catch (...) {
+       }
+}

Added: 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// void push_front(const value_type& x);
+
+#include <deque>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::deque<CMyClass> vec;
+
+       vec.push_front(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_front(instance);
+       }
+       catch (...) {
+       }
+}

Added: 
libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// void push_front(const value_type& x);
+
+#include <forward_list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::forward_list<CMyClass> vec;
+
+       vec.push_front(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_front(instance);
+       }
+       catch (...) {
+       }
+}

Added: 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// void push_back(const value_type& x);
+
+#include <list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::list<CMyClass> vec;
+
+       vec.push_back(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_back(instance);
+       }
+       catch (...) {
+       }
+}

Added: 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// void push_front(const value_type& x);
+
+#include <list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::list<CMyClass> vec;
+
+       vec.push_front(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_front(instance);
+       }
+       catch (...) {
+       }
+}

Added: 
libcxx/trunk/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
URL: 
http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp?rev=172250&view=auto
==============================================================================
--- 
libcxx/trunk/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
 (added)
+++ 
libcxx/trunk/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
 Fri Jan 11 14:36:59 2013
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// void push_back(const value_type& x);
+
+#include <vector>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+       public: CMyClass();
+       public: CMyClass(const CMyClass& iOther);
+       public: ~CMyClass();
+
+       private: int fMagicValue;
+
+       private: static int kStartedConstructionMagicValue;
+       private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet 
finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+       fMagicValue(kStartedConstructionMagicValue)
+{
+       // If requested, throw an exception _before_ setting fMagicValue to 
kFinishedConstructionMagicValue
+       if (gCopyConstructorShouldThow) {
+               throw std::exception();
+       }
+       // Signal that the constructor has finished running
+       fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+       // Only instances for which the constructor has finished running should 
be destructed
+       assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+       CMyClass instance;
+       std::vector<CMyClass> vec;
+
+       vec.push_back(instance);
+
+       gCopyConstructorShouldThow = true;
+       try {
+               vec.push_back(instance);
+       }
+       catch (...) {
+       }
+}


_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to