From 6135d0d803084f6c2dd8672df1bef4c6e58f9e19 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Mar 2016 20:31:13 +0100 Subject: [PATCH 1/4] patch 7.4.1636 Problem: When 'F' is in 'shortmess' the prompt for the encryption key isn't displayed. (Toothpik) Solution: Reset msg_silent. --- src/ex_getln.c | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/ex_getln.c b/src/ex_getln.c index 8419d3f2c2..740c4b6cf9 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1989,6 +1989,7 @@ getcmdline_prompt( char_u *s; struct cmdline_info save_ccline; int msg_col_save = msg_col; + int msg_silent_save = msg_silent; save_cmdline(&save_ccline); ccline.cmdprompt = prompt; @@ -1998,8 +1999,10 @@ getcmdline_prompt( ccline.xp_arg = xp_arg; ccline.input_fn = (firstc == '@'); # endif + msg_silent = 0; s = getcmdline(firstc, 1L, 0); restore_cmdline(&save_ccline); + msg_silent = msg_silent_save; /* Restore msg_col, the prompt from input() may have changed it. * But only if called recursively and the commandline is therefore being * restored to an old one; if not, the input() prompt stays on the screen, diff --git a/src/version.c b/src/version.c index 75ae6149b8..d28ad946a2 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1636, /**/ 1635, /**/ From 6c0e984f263fc1eef42c9b34a80eff1bceb8d05b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Mar 2016 20:42:31 +0100 Subject: [PATCH 2/4] patch 7.4.1637 Problem: Can't build with older MinGW compiler. Solution: Change option from c++11 to gnu++11. (Ken Takata) --- src/Make_cyg_ming.mak | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 9bb26aa6da..62585e9961 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -415,7 +415,7 @@ WINDRES_CC = $(CC) ########################################################################### CFLAGS = -Iproto $(DEFINES) -pipe -march=$(ARCH) -Wall -CXXFLAGS = -std=c++11 +CXXFLAGS = -std=gnu++11 WINDRES_FLAGS = --preprocessor="$(WINDRES_CC) -E -xc" -DRC_INVOKED EXTRA_LIBS = diff --git a/src/version.c b/src/version.c index d28ad946a2..c9f1926acf 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1637, /**/ 1636, /**/ From e4eb6ff089e79e659acf33c17dd0fda7177de526 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Mar 2016 21:00:09 +0100 Subject: [PATCH 3/4] patch 7.4.1638 Problem: When binding a function to a dict the reference count is wrong. Solution: Decrement dict reference count, only reference the function when actually making a copy. (Ken Takata) --- src/eval.c | 10 +++++++--- src/testdir/test_partial.vim | 10 ++++++++++ src/version.c | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/eval.c b/src/eval.c index b2338331f5..d922e6aef9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -12019,6 +12019,7 @@ partial_free(partial_T *pt) for (i = 0; i < pt->pt_argc; ++i) clear_tv(&pt->pt_argv[i]); vim_free(pt->pt_argv); + dict_unref(pt->pt_dict); func_unref(pt->pt_name); vim_free(pt->pt_name); vim_free(pt); @@ -21797,7 +21798,8 @@ handle_subscript( selfdict = NULL; if (rettv->v_type == VAR_FUNC) { - /* just a function: use selfdict */ + /* Just a function: Take over the function name and use + * selfdict. */ pt->pt_name = rettv->vval.v_string; } else @@ -21805,8 +21807,11 @@ handle_subscript( partial_T *ret_pt = rettv->vval.v_partial; int i; - /* partial: use selfdict and copy args */ + /* Partial: copy the function name, use selfdict and copy + * args. Can't take over name or args, the partial might + * be referenced elsewhere. */ pt->pt_name = vim_strsave(ret_pt->pt_name); + func_ref(pt->pt_name); if (ret_pt->pt_argc > 0) { pt->pt_argv = (typval_T *)alloc( @@ -21823,7 +21828,6 @@ handle_subscript( } partial_unref(ret_pt); } - func_ref(pt->pt_name); rettv->v_type = VAR_PARTIAL; rettv->vval.v_partial = pt; } diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim index 3764f221fc..f67bb41dd8 100644 --- a/src/testdir/test_partial.vim +++ b/src/testdir/test_partial.vim @@ -170,3 +170,13 @@ func Test_partial_string() let F = function('MyFunc', ['foo'], d) call assert_equal("function('MyFunc', ['foo'], {'one': 1})", string(F)) endfunc + +func Test_func_unref() + let obj = {} + function! obj.func() abort + endfunction + let funcnumber = matchstr(string(obj.func), '^function(''\zs.\{-}\ze''') + call assert_true(exists('*{' . funcnumber . '}')) + unlet obj + call assert_false(exists('*{' . funcnumber . '}')) +endfunc diff --git a/src/version.c b/src/version.c index c9f1926acf..1a02fbe921 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1638, /**/ 1637, /**/ From 5f436fcf9960c95702820d5ac1b8b612995f6c04 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Mar 2016 22:34:03 +0100 Subject: [PATCH 4/4] patch 7.4.1639 Problem: Invoking garbage collection may cause a double free. Solution: Don't free the dict in a partial when recursive is FALSE. --- src/eval.c | 77 ++++++++++++++++++++++++++++++++------------------- src/version.c | 2 ++ 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/eval.c b/src/eval.c index d922e6aef9..990fa8c05b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -209,7 +209,9 @@ static hashtab_T func_hashtab; /* The names of packages that once were loaded are remembered. */ static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL}; -/* list heads for garbage collection */ +/* List heads for garbage collection. Although there can be a reference loop + * from partial to dict to partial, we don't need to keep track of the partial, + * since it will get freed when the dict is unused and gets freed. */ static dict_T *first_dict = NULL; /* list of all dicts */ static list_T *first_list = NULL; /* list of all lists */ @@ -7130,9 +7132,14 @@ set_ref_in_item( list_T *ll; int abort = FALSE; - if (tv->v_type == VAR_DICT) + if (tv->v_type == VAR_DICT || tv->v_type == VAR_PARTIAL) { - dd = tv->vval.v_dict; + if (tv->v_type == VAR_DICT) + dd = tv->vval.v_dict; + else if (tv->vval.v_partial != NULL) + dd = tv->vval.v_partial->pt_dict; + else + dd = NULL; if (dd != NULL && dd->dv_copyID != copyID) { /* Didn't see this dict yet. */ @@ -7184,6 +7191,32 @@ set_ref_in_item( return abort; } + static void +partial_free(partial_T *pt, int free_dict) +{ + int i; + + for (i = 0; i < pt->pt_argc; ++i) + clear_tv(&pt->pt_argv[i]); + vim_free(pt->pt_argv); + if (free_dict) + dict_unref(pt->pt_dict); + func_unref(pt->pt_name); + vim_free(pt->pt_name); + vim_free(pt); +} + +/* + * Unreference a closure: decrement the reference count and free it when it + * becomes zero. + */ + void +partial_unref(partial_T *pt) +{ + if (pt != NULL && --pt->pt_refcount <= 0) + partial_free(pt, TRUE); +} + /* * Allocate an empty header for a dictionary. */ @@ -7275,7 +7308,18 @@ dict_free( hash_remove(&d->dv_hashtab, hi); if (recurse || (di->di_tv.v_type != VAR_LIST && di->di_tv.v_type != VAR_DICT)) - clear_tv(&di->di_tv); + { + if (!recurse && di->di_tv.v_type == VAR_PARTIAL) + { + partial_T *pt = di->di_tv.vval.v_partial; + + /* We unref the partial but not the dict it refers to. */ + if (pt != NULL && --pt->pt_refcount == 0) + partial_free(pt, FALSE); + } + else + clear_tv(&di->di_tv); + } vim_free(di); --todo; } @@ -12011,31 +12055,6 @@ f_function(typval_T *argvars, typval_T *rettv) } } - static void -partial_free(partial_T *pt) -{ - int i; - - for (i = 0; i < pt->pt_argc; ++i) - clear_tv(&pt->pt_argv[i]); - vim_free(pt->pt_argv); - dict_unref(pt->pt_dict); - func_unref(pt->pt_name); - vim_free(pt->pt_name); - vim_free(pt); -} - -/* - * Unreference a closure: decrement the reference count and free it when it - * becomes zero. - */ - void -partial_unref(partial_T *pt) -{ - if (pt != NULL && --pt->pt_refcount <= 0) - partial_free(pt); -} - /* * "garbagecollect()" function */ diff --git a/src/version.c b/src/version.c index 1a02fbe921..6fffeeb761 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1639, /**/ 1638, /**/