[libcxx] r323390 - Fix PR35564 - std::list splice/erase incorrectly throw in debug mode.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 24 16:02:48 PST 2018


Author: ericwf
Date: Wed Jan 24 16:02:48 2018
New Revision: 323390

URL: http://llvm.org/viewvc/llvm-project?rev=323390&view=rev
Log:
Fix PR35564 - std::list splice/erase incorrectly throw in debug mode.

There was a bug in the implementation of splice where the container
sizes were updated before decrementing one of the iterators. Afterwards,
the result of decrementing the iterator was flagged as UB by the debug
implementation because the container was reported to be empty.

This patch fixes that bug by delaying the updating of the container
sizes until after the iterators have been correctly constructed.

Modified:
    libcxx/trunk/include/list
    libcxx/trunk/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp

Modified: libcxx/trunk/include/list
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/list?rev=323390&r1=323389&r2=323390&view=diff
==============================================================================
--- libcxx/trunk/include/list (original)
+++ libcxx/trunk/include/list Wed Jan 24 16:02:48 2018
@@ -2058,15 +2058,15 @@ list<_Tp, _Alloc>::splice(const_iterator
 #endif
     if (__f != __l)
     {
+        __link_pointer __first = __f.__ptr_;
+        --__l;
+        __link_pointer __last = __l.__ptr_;
         if (this != &__c)
         {
-            size_type __s = _VSTD::distance(__f, __l);
+            size_type __s = _VSTD::distance(__f, __l) + 1;
             __c.__sz() -= __s;
             base::__sz() += __s;
         }
-        __link_pointer __first = __f.__ptr_;
-        --__l;
-        __link_pointer __last = __l.__ptr_;
         base::__unlink_nodes(__first, __last);
         __link_nodes(__p.__ptr_, __first, __last);
 #if _LIBCPP_DEBUG_LEVEL >= 2

Modified: libcxx/trunk/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp?rev=323390&r1=323389&r2=323390&view=diff
==============================================================================
--- libcxx/trunk/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp Wed Jan 24 16:02:48 2018
@@ -42,6 +42,7 @@ public:
     Base::run();
     try {
       FrontOnEmptyContainer();
+
       if constexpr (CT != CT_ForwardList) {
         AssignInvalidates();
         BackOnEmptyContainer();
@@ -50,6 +51,8 @@ public:
         InsertIterIterIter();
         EmplaceIterValue();
         EraseIterIter();
+      } else {
+        SpliceFirstElemAfter();
       }
       if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
         PopBack();
@@ -57,12 +60,66 @@ public:
       if constexpr (CT == CT_List || CT == CT_Deque) {
         PopFront(); // FIXME: Run with forward list as well
       }
+      if constexpr (CT == CT_List || CT == CT_ForwardList) {
+        RemoveFirstElem();
+      }
+      if constexpr (CT == CT_List) {
+        SpliceFirstElem();
+      }
     } catch (...) {
       assert(false && "uncaught debug exception");
     }
   }
 
 private:
+  static void RemoveFirstElem() {
+    // See llvm.org/PR35564
+    CHECKPOINT("remove(<first-elem>)");
+    {
+      Container C = makeContainer(1);
+      auto FirstVal = *(C.begin());
+      C.remove(FirstVal);
+      assert(C.empty());
+    }
+    {
+      Container C = {1, 1, 1, 1};
+      auto FirstVal = *(C.begin());
+      C.remove(FirstVal);
+      assert(C.empty());
+    }
+  }
+
+  static void SpliceFirstElem() {
+    // See llvm.org/PR35564
+    CHECKPOINT("splice(<first-elem>)");
+    {
+      Container C = makeContainer(1);
+      Container C2;
+      C2.splice(C2.end(), C, C.begin(), ++C.begin());
+    }
+    {
+      Container C = makeContainer(1);
+      Container C2;
+      C2.splice(C2.end(), C, C.begin());
+    }
+  }
+
+
+  static void SpliceFirstElemAfter() {
+    // See llvm.org/PR35564
+    CHECKPOINT("splice(<first-elem>)");
+    {
+      Container C = makeContainer(1);
+      Container C2;
+      C2.splice_after(C2.begin(), C, C.begin(), ++C.begin());
+    }
+    {
+      Container C = makeContainer(1);
+      Container C2;
+      C2.splice_after(C2.begin(), C, C.begin());
+    }
+  }
+
   static void AssignInvalidates() {
     CHECKPOINT("assign(Size, Value)");
     Container C(allocator_type{});




More information about the cfe-commits mailing list