diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-07 16:08:08 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-07 16:08:08 +0200 |
commit | 5b157fe2edfdce5f77080aeac2b4a03f39eb1c1a (patch) | |
tree | e2757dfeb60d92934e3cd0900d9eb43769389f56 /src | |
parent | 673fc3e23f09095d17f0095c4323958041b2d0d2 (diff) |
patch 8.2.0920: writing viminfo fails with a circular referencev8.2.0920
Problem: Writing viminfo fails with a circular reference.
Solution: Use copyID to detect the cycle. (closes #6217)
Diffstat (limited to 'src')
-rw-r--r-- | src/testdir/test_viminfo.vim | 22 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/viminfo.c | 30 |
3 files changed, 52 insertions, 2 deletions
diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim index b4708f5f89..8650598216 100644 --- a/src/testdir/test_viminfo.vim +++ b/src/testdir/test_viminfo.vim @@ -91,6 +91,28 @@ func Test_global_vars() set viminfo-=! endfunc +func Test_global_vars_with_circular_reference() + let g:MY_GLOBAL_LIST = [] + call add(g:MY_GLOBAL_LIST, g:MY_GLOBAL_LIST) + let g:MY_GLOBAL_DICT = {} + let g:MY_GLOBAL_DICT['self'] = g:MY_GLOBAL_DICT + + set viminfo='100,<50,s10,h,!,nviminfo + wv! Xviminfo + call assert_equal(v:errmsg, '') + + unlet g:MY_GLOBAL_LIST + unlet g:MY_GLOBAL_DICT + + rv! Xviminfo + call assert_equal(v:errmsg, '') + call assert_true(!exists('g:MY_GLOBAL_LIST')) + call assert_true(!exists('g:MY_GLOBAL_DICT')) + + call delete('Xviminfo') + set viminfo-=! +endfunc + func Test_cmdline_history() call histdel(':') call test_settime(11) diff --git a/src/version.c b/src/version.c index 36207450c2..c400df423f 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 920, +/**/ 919, /**/ 918, diff --git a/src/viminfo.c b/src/viminfo.c index b014d7f215..4f26348a22 100644 --- a/src/viminfo.c +++ b/src/viminfo.c @@ -1337,8 +1337,34 @@ write_viminfo_varlist(FILE *fp) case VAR_STRING: s = "STR"; break; case VAR_NUMBER: s = "NUM"; break; case VAR_FLOAT: s = "FLO"; break; - case VAR_DICT: s = "DIC"; break; - case VAR_LIST: s = "LIS"; break; + case VAR_DICT: + { + dict_T *di = this_var->di_tv.vval.v_dict; + int copyID = get_copyID(); + + s = "DIC"; + if (di != NULL && !set_ref_in_ht( + &di->dv_hashtab, copyID, NULL) + && di->dv_copyID == copyID) + // has a circular reference, can't turn the + // value into a string + continue; + break; + } + case VAR_LIST: + { + list_T *l = this_var->di_tv.vval.v_list; + int copyID = get_copyID(); + + s = "LIS"; + if (l != NULL && !set_ref_in_list_items( + l, copyID, NULL) + && l->lv_copyID == copyID) + // has a circular reference, can't turn the + // value into a string + continue; + break; + } case VAR_BLOB: s = "BLO"; break; case VAR_BOOL: s = "XPL"; break; // backwards compat. case VAR_SPECIAL: s = "XPL"; break; |