diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-04-08 20:10:10 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-04-08 20:10:10 +0200 |
commit | dcae51facc4d6de1edd62f0242b40972be841103 (patch) | |
tree | cc4ed54ec096b1fb0e036166274d36ea64940990 | |
parent | d8db8383926cb8729417d9515cbfaf455dbbd8d1 (diff) | |
download | vim-git-dcae51facc4d6de1edd62f0242b40972be841103.tar.gz |
patch 8.2.2738: extending a list with itself can give wrong resultv8.2.2738
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)
-rw-r--r-- | src/list.c | 9 | ||||
-rw-r--r-- | src/testdir/test_listdict.vim | 14 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 24 insertions, 1 deletions
diff --git a/src/list.c b/src/list.c index 873f9e63d..76327abc8 100644 --- a/src/list.c +++ b/src/list.c @@ -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; diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 051a37c3a..1b0796d81 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -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() diff --git a/src/version.c b/src/version.c index 1a1f23784..452565c1f 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2738, +/**/ 2737, /**/ 2736, |