]> granicus.if.org Git - vim/commitdiff
patch 8.2.2738: extending a list with itself can give wrong result v8.2.2738
authorBram Moolenaar <Bram@vim.org>
Thu, 8 Apr 2021 18:10:10 +0000 (20:10 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 8 Apr 2021 18:10:10 +0000 (20:10 +0200)
Problem:    Extending a list with itself can give wrong result.
Solution:   Remember the item before where the insertion happens and skip to
            after the already inserted items. (closes #1112)

src/list.c
src/testdir/test_listdict.vim
src/version.c

index 873f9e63de5db6f7bea0cc9d91fd986ee1a8fcd2..76327abc87c60ffaafe2d1ed77a64df745666b17 100644 (file)
@@ -894,6 +894,7 @@ list_extend(list_T *l1, list_T *l2, listitem_T *bef)
 {
     listitem_T *item;
     int                todo;
+    listitem_T *bef_prev;
 
     // NULL list is equivalent to an empty list: nothing to do.
     if (l2 == NULL || l2->lv_len == 0)
@@ -903,9 +904,15 @@ list_extend(list_T *l1, list_T *l2, listitem_T *bef)
     CHECK_LIST_MATERIALIZE(l1);
     CHECK_LIST_MATERIALIZE(l2);
 
+    // When exending a list with itself, at some point we run into the item
+    // that was before "bef" and need to skip over the already inserted items
+    // to "bef".
+    bef_prev = bef == NULL ? NULL : bef->li_prev;
+
     // We also quit the loop when we have inserted the original item count of
     // the list, avoid a hang when we extend a list with itself.
-    for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next)
+    for (item = l2->lv_first; item != NULL && --todo >= 0;
+                                item = item == bef_prev ? bef : item->li_next)
        if (list_insert_tv(l1, &item->li_tv, bef) == FAIL)
            return FAIL;
     return OK;
index 051a37c3a533e92d59325218270326c2b31936cf..1b0796d81608ae4442368283489aacc85db3f769 100644 (file)
@@ -862,6 +862,20 @@ func Test_listdict_extend()
 
   " Extend g: dictionary with an invalid variable name
   call assert_fails("call extend(g:, {'-!' : 10})", 'E461:')
+
+  " Extend a list with itself.
+  let l = [1, 5, 7]
+  call extend(l, l, 0)
+  call assert_equal([1, 5, 7, 1, 5, 7], l)
+  let l = [1, 5, 7]
+  call extend(l, l, 1)
+  call assert_equal([1, 1, 5, 7, 5, 7], l)
+  let l = [1, 5, 7]
+  call extend(l, l, 2)
+  call assert_equal([1, 5, 1, 5, 7, 7], l)
+  let l = [1, 5, 7]
+  call extend(l, l, 3)
+  call assert_equal([1, 5, 7, 1, 5, 7], l)
 endfunc
 
 func Test_listdict_extendnew()
index 1a1f23784396dba32835fb9ad66ac348238fa0fe..452565c1f246ae5012caa4dc8ce98c58c9658f78 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2738,
 /**/
     2737,
 /**/