diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-24 20:34:03 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-24 20:34:03 +0200 |
commit | b171fb179053fa631fec74911b5fb9374cb6a8a1 (patch) | |
tree | c45ae9287bf07033cc4f3bf43529b7548ba432c9 | |
parent | 9d40c63c7dc8c3eb3886c58dcd334bc7f37eceba (diff) | |
download | vim-git-b171fb179053fa631fec74911b5fb9374cb6a8a1.tar.gz |
patch 8.2.1049: Vim9: leaking memory when using continuation linev8.2.1049
Problem: Vim9: leaking memory when using continuation line.
Solution: Keep a pointer to the continuation line in evalarg_T. Centralize
checking for a next command.
-rw-r--r-- | src/beval.c | 2 | ||||
-rw-r--r-- | src/buffer.c | 4 | ||||
-rw-r--r-- | src/clientserver.c | 2 | ||||
-rw-r--r-- | src/eval.c | 70 | ||||
-rw-r--r-- | src/evalvars.c | 2 | ||||
-rw-r--r-- | src/ex_docmd.c | 3 | ||||
-rw-r--r-- | src/ex_eval.c | 12 | ||||
-rw-r--r-- | src/filepath.c | 2 | ||||
-rw-r--r-- | src/findfile.c | 2 | ||||
-rw-r--r-- | src/fold.c | 2 | ||||
-rw-r--r-- | src/globals.h | 2 | ||||
-rw-r--r-- | src/if_ole.cpp | 2 | ||||
-rw-r--r-- | src/if_perl.xs | 3 | ||||
-rw-r--r-- | src/if_tcl.c | 2 | ||||
-rw-r--r-- | src/map.c | 2 | ||||
-rw-r--r-- | src/proto/eval.pro | 16 | ||||
-rw-r--r-- | src/quickfix.c | 2 | ||||
-rw-r--r-- | src/regexp.c | 2 | ||||
-rw-r--r-- | src/register.c | 2 | ||||
-rw-r--r-- | src/screen.c | 2 | ||||
-rw-r--r-- | src/structs.h | 3 | ||||
-rw-r--r-- | src/userfunc.c | 4 | ||||
-rw-r--r-- | src/version.c | 2 |
23 files changed, 90 insertions, 55 deletions
diff --git a/src/beval.c b/src/beval.c index b7d9226e7..dd7bc3cdc 100644 --- a/src/beval.c +++ b/src/beval.c @@ -285,7 +285,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) ++textwinlock; vim_free(result); - result = eval_to_string(bexpr, NULL, TRUE); + result = eval_to_string(bexpr, TRUE); // Remove one trailing newline, it is added when the result was a // list and it's hardly ever useful. If the user really wants a diff --git a/src/buffer.c b/src/buffer.c index f928412e8..40ca25dfa 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4094,7 +4094,7 @@ build_stl_str_hl( tv.vval.v_number = wp->w_id; set_var((char_u *)"g:statusline_winid", &tv, FALSE); - usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); + usefmt = eval_to_string_safe(fmt + 2, use_sandbox); if (usefmt == NULL) usefmt = fmt; @@ -4434,7 +4434,7 @@ build_stl_str_hl( if (curwin != save_curwin) VIsual_active = FALSE; - str = eval_to_string_safe(p, &t, use_sandbox); + str = eval_to_string_safe(p, use_sandbox); curwin = save_curwin; curbuf = save_curbuf; diff --git a/src/clientserver.c b/src/clientserver.c index cf35c8149..fbbeb6a4b 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -86,7 +86,7 @@ eval_client_expr_to_string(char_u *expr) // to be typed. Do generate errors so that try/catch works. ++emsg_silent; - res = eval_to_string(expr, NULL, TRUE); + res = eval_to_string(expr, TRUE); debug_break_level = save_dbl; redir_off = save_ro; diff --git a/src/eval.c b/src/eval.c index ffb69de8d..79944c8ca 100644 --- a/src/eval.c +++ b/src/eval.c @@ -161,7 +161,7 @@ eval_clear(void) eval_to_bool( char_u *arg, int *error, - char_u **nextcmd, + exarg_T *eap, int skip) // only parse, don't execute { typval_T tv; @@ -169,7 +169,7 @@ eval_to_bool( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) == FAIL) + if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL) *error = TRUE; else { @@ -317,7 +317,7 @@ eval_expr_to_bool(typval_T *expr, int *error) char_u * eval_to_string_skip( char_u *arg, - char_u **nextcmd, + exarg_T *eap, int skip) // only parse, don't execute { typval_T tv; @@ -325,7 +325,7 @@ eval_to_string_skip( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? NULL : &EVALARG_EVALUATE) + if (eval0(arg, &tv, eap, skip ? NULL : &EVALARG_EVALUATE) == FAIL || skip) retval = NULL; else @@ -361,7 +361,6 @@ skip_expr(char_u **pp) char_u * eval_to_string( char_u *arg, - char_u **nextcmd, int convert) { typval_T tv; @@ -371,7 +370,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, &EVALARG_EVALUATE) == FAIL) + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) retval = NULL; else { @@ -409,7 +408,6 @@ eval_to_string( char_u * eval_to_string_safe( char_u *arg, - char_u **nextcmd, int use_sandbox) { char_u *retval; @@ -419,7 +417,7 @@ eval_to_string_safe( if (use_sandbox) ++sandbox; ++textwinlock; - retval = eval_to_string(arg, nextcmd, FALSE); + retval = eval_to_string(arg, FALSE); if (use_sandbox) --sandbox; --textwinlock; @@ -459,12 +457,12 @@ eval_to_number(char_u *expr) * Returns NULL when there is an error. */ typval_T * -eval_expr(char_u *arg, char_u **nextcmd) +eval_expr(char_u *arg, exarg_T *eap) { typval_T *tv; tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, &EVALARG_EVALUATE) == FAIL) + if (tv != NULL && eval0(arg, tv, eap, &EVALARG_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; @@ -1418,7 +1416,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) eval_for_line( char_u *arg, int *errp, - char_u **nextcmdp, + exarg_T *eap, int skip) { forinfo_T *fi; @@ -1448,7 +1446,7 @@ eval_for_line( if (skip) ++emsg_skip; - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, &evalarg) == OK) + if (eval0(skipwhite(expr + 2), &tv, eap, &evalarg) == OK) { *errp = FALSE; if (!skip) @@ -1796,6 +1794,17 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) } /* + * To be called when eval_next_non_blank() sets "getnext" to TRUE. + */ + static char_u * +eval_next_line(evalarg_T *evalarg) +{ + vim_free(evalarg->eval_tofree); + evalarg->eval_tofree = getsourceline(0, evalarg->eval_cookie, 0, TRUE); + return skipwhite(evalarg->eval_tofree); +} + +/* * The "evaluate" argument: When FALSE, the argument is only parsed but not * executed. The function may return OK, but the rettv will be of type * VAR_UNKNOWN. The function still returns FAIL for a syntax error. @@ -1813,7 +1822,7 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) eval0( char_u *arg, typval_T *rettv, - char_u **nextcmd, + exarg_T *eap, evalarg_T *evalarg) { int ret; @@ -1822,8 +1831,11 @@ eval0( int called_emsg_before = called_emsg; int flags = evalarg == NULL ? 0 : evalarg->eval_flags; + if (evalarg != NULL) + evalarg->eval_tofree = NULL; p = skipwhite(arg); ret = eval1(&p, rettv, evalarg); + if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) @@ -1841,8 +1853,27 @@ eval0( semsg(_(e_invexpr2), arg); ret = FAIL; } - if (nextcmd != NULL) - *nextcmd = check_nextcmd(p); + + if (eap != NULL) + eap->nextcmd = check_nextcmd(p); + + if (evalarg != NULL) + { + if (eap != NULL) + { + if (evalarg->eval_tofree != NULL) + { + // We may need to keep the original command line, e.g. for + // ":let" it has the variable names. But we may also need the + // new one, "nextcmd" points into it. Keep both. + vim_free(eap->cmdline_tofree); + eap->cmdline_tofree = *eap->cmdlinep; + *eap->cmdlinep = evalarg->eval_tofree; + } + } + else + vim_free(evalarg->eval_tofree); + } return ret; } @@ -2305,7 +2336,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) if (op != '+' && op != '-' && !concat) break; if (getnext) - *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE)); + *arg = eval_next_line(evalarg); if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) @@ -2497,7 +2528,7 @@ eval6( if (op != '*' && op != '/' && op != '%') break; if (getnext) - *arg = skipwhite(getsourceline(0, evalarg->eval_cookie, 0, TRUE)); + *arg = eval_next_line(evalarg); if (evaluate) { @@ -4734,7 +4765,6 @@ make_expanded_name( char_u c1; char_u *retval = NULL; char_u *temp_result; - char_u *nextcmd = NULL; if (expr_end == NULL || in_end == NULL) return NULL; @@ -4743,8 +4773,8 @@ make_expanded_name( c1 = *in_end; *in_end = NUL; - temp_result = eval_to_string(expr_start + 1, &nextcmd, FALSE); - if (temp_result != NULL && nextcmd == NULL) + temp_result = eval_to_string(expr_start + 1, FALSE); + if (temp_result != NULL) { retval = alloc(STRLEN(temp_result) + (expr_start - in_start) + (in_end - expr_end) + 1); diff --git a/src/evalvars.c b/src/evalvars.c index 35c9dcb73..e64b44ed1 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -800,7 +800,7 @@ ex_let(exarg_T *eap) evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL; - i = eval0(expr, &rettv, &eap->nextcmd, &evalarg); + i = eval0(expr, &rettv, eap, &evalarg); if (eap->skip) --emsg_skip; } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 4755a01b4..6c887fae1 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2609,6 +2609,7 @@ doend: #ifdef FEAT_EVAL --ex_nesting_level; + vim_free(ea.cmdline_tofree); #endif return ea.nextcmd; @@ -4912,7 +4913,7 @@ ex_colorscheme(exarg_T *eap) if (expr != NULL) { ++emsg_off; - p = eval_to_string(expr, NULL, FALSE); + p = eval_to_string(expr, FALSE); --emsg_off; vim_free(expr); } diff --git a/src/ex_eval.c b/src/ex_eval.c index cb32bd079..8b8a25695 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -900,7 +900,7 @@ ex_eval(exarg_T *eap) evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; evalarg.eval_cookie = eap->getline == getsourceline ? eap->cookie : NULL; - if (eval0(eap->arg, &tv, &eap->nextcmd, &evalarg) == OK) + if (eval0(eap->arg, &tv, eap, &evalarg) == OK) clear_tv(&tv); } @@ -929,7 +929,7 @@ ex_if(exarg_T *eap) skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0 && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)); - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); if (!skip && !error) { @@ -1041,7 +1041,7 @@ ex_else(exarg_T *eap) if (eap->cmdidx == CMD_elseif) { - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); // When throwing error exceptions, we want to throw always the first // of several errors in a row. This is what actually happens when @@ -1103,7 +1103,7 @@ ex_while(exarg_T *eap) /* * ":while bool-expr" */ - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); } else { @@ -1122,7 +1122,7 @@ ex_while(exarg_T *eap) else { // Evaluate the argument and get the info in a structure. - fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip); + fi = eval_for_line(eap->arg, &error, eap, skip); cstack->cs_forinfo[cstack->cs_idx] = fi; } @@ -1322,7 +1322,7 @@ ex_throw(exarg_T *eap) char_u *value; if (*arg != NUL && *arg != '|' && *arg != '\n') - value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip); + value = eval_to_string_skip(arg, eap, eap->skip); else { emsg(_(e_argreq)); diff --git a/src/filepath.c b/src/filepath.c index 1fe757e85..6644e9939 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -3083,7 +3083,7 @@ expand_backtick( #ifdef FEAT_EVAL if (*cmd == '=') // `={expr}`: Expand expression - buffer = eval_to_string(cmd + 1, &p, TRUE); + buffer = eval_to_string(cmd + 1, TRUE); else #endif buffer = get_cmd_output(cmd, NULL, diff --git a/src/findfile.c b/src/findfile.c index b153ed010..190fc69dc 100644 --- a/src/findfile.c +++ b/src/findfile.c @@ -2079,7 +2079,7 @@ eval_includeexpr(char_u *ptr, int len) char_u *res; set_vim_var_string(VV_FNAME, ptr, len); - res = eval_to_string_safe(curbuf->b_p_inex, NULL, + res = eval_to_string_safe(curbuf->b_p_inex, was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL)); set_vim_var_string(VV_FNAME, NULL, 0); return res; diff --git a/src/fold.c b/src/fold.c index d91203c75..043037fa6 100644 --- a/src/fold.c +++ b/src/fold.c @@ -1928,7 +1928,7 @@ get_foldtext( curbuf = wp->w_buffer; ++emsg_silent; // handle exceptions, but don't display errors - text = eval_to_string_safe(wp->w_p_fdt, NULL, + text = eval_to_string_safe(wp->w_p_fdt, was_set_insecurely((char_u *)"foldtext", OPT_LOCAL)); --emsg_silent; diff --git a/src/globals.h b/src/globals.h index 8601e2b1e..c7f9794ab 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1882,7 +1882,7 @@ EXTERN char windowsVersion[20] INIT(= {0}); EXTERN listitem_T range_list_item; // Passed to an eval() function to enable evaluation. -EXTERN evalarg_T EVALARG_EVALUATE INIT2(EVAL_EVALUATE, NULL); +EXTERN evalarg_T EVALARG_EVALUATE INIT3(EVAL_EVALUATE, NULL, NULL); #endif #ifdef MSWIN diff --git a/src/if_ole.cpp b/src/if_ole.cpp index 34ce23266..e415a1924 100644 --- a/src/if_ole.cpp +++ b/src/if_ole.cpp @@ -388,7 +388,7 @@ CVim::Eval(BSTR expr, BSTR *result) /* Evaluate the expression */ ++emsg_skip; - str = (char *)eval_to_string((char_u *)buffer, NULL, TRUE); + str = (char *)eval_to_string((char_u *)buffer, TRUE); --emsg_skip; vim_free(buffer); if (str == NULL) diff --git a/src/if_perl.xs b/src/if_perl.xs index bf269cbcb..cad571c5c 100644 --- a/src/if_perl.xs +++ b/src/if_perl.xs @@ -832,7 +832,6 @@ msg_split( char_u * eval_to_string( char_u *arg UNUSED, - char_u **nextcmd UNUSED, int dolist UNUSED) { return NULL; @@ -1562,7 +1561,7 @@ Eval(str) PREINIT: char_u *value; PPCODE: - value = eval_to_string((char_u *)str, (char_u **)0, TRUE); + value = eval_to_string((char_u *)str, TRUE); if (value == NULL) { XPUSHs(sv_2mortal(newSViv(0))); diff --git a/src/if_tcl.c b/src/if_tcl.c index c274b2675..2775221f4 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -1373,7 +1373,7 @@ tclvimexpr( #ifdef FEAT_EVAL expr = Tcl_GetStringFromObj(objv[objn], NULL); - str = (char *)eval_to_string((char_u *)expr, NULL, TRUE); + str = (char *)eval_to_string((char_u *)expr, TRUE); if (str == NULL) Tcl_SetResult(interp, _("invalid expression"), TCL_STATIC); else @@ -1614,7 +1614,7 @@ eval_map_expr( save_cursor = curwin->w_cursor; save_msg_col = msg_col; save_msg_row = msg_row; - p = eval_to_string(expr, NULL, FALSE); + p = eval_to_string(expr, FALSE); --textwinlock; --ex_normal_lock; curwin->w_cursor = save_cursor; diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 4fb04eb1f..87e447808 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -3,16 +3,16 @@ varnumber_T num_divide(varnumber_T n1, varnumber_T n2); varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); void eval_init(void); void eval_clear(void); -int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip); +int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip); int eval_expr_valid_arg(typval_T *tv); int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv); int eval_expr_to_bool(typval_T *expr, int *error); -char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip); +char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip); int skip_expr(char_u **pp); -char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert); -char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox); +char_u *eval_to_string(char_u *arg, int convert); +char_u *eval_to_string_safe(char_u *arg, int use_sandbox); varnumber_T eval_to_number(char_u *expr); -typval_T *eval_expr(char_u *arg, char_u **nextcmd); +typval_T *eval_expr(char_u *arg, exarg_T *eap); int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv); varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv); void *call_func_retstr(char_u *func, int argc, typval_T *argv); @@ -21,13 +21,13 @@ int eval_foldexpr(char_u *arg, int *cp); char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags); void clear_lval(lval_T *lp); void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int flags, char_u *op); -void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip); +void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, int skip); int next_for_item(void *fi_void, char_u *arg); void free_for_info(void *fi_void); void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx); int pattern_match(char_u *pat, char_u *text, int ic); -int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, evalarg_T *evalarg); -int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg_in); +int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); +int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg); void eval_addblob(typval_T *tv1, typval_T *tv2); int eval_addlist(typval_T *tv1, typval_T *tv2); char_u *partial_name(partial_T *pt); diff --git a/src/quickfix.c b/src/quickfix.c index ba54fab9c..3bd0f75e2 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -7680,7 +7680,7 @@ ex_cexpr(exarg_T *eap) // Evaluate the expression. When the result is a string or a list we can // use it to fill the errorlist. - tv = eval_expr(eap->arg, &eap->nextcmd); + tv = eval_expr(eap->arg, eap); if (tv != NULL) { if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) diff --git a/src/regexp.c b/src/regexp.c index de0b0fad4..229f6ef2b 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -2066,7 +2066,7 @@ vim_regsub_both( clear_tv(&rettv); } else - eval_result = eval_to_string(source + 2, NULL, TRUE); + eval_result = eval_to_string(source + 2, TRUE); if (eval_result != NULL) { diff --git a/src/register.c b/src/register.c index 49f7a7c86..66dd0cca6 100644 --- a/src/register.c +++ b/src/register.c @@ -136,7 +136,7 @@ get_expr_line(void) return expr_copy; ++nested; - rv = eval_to_string(expr_copy, NULL, TRUE); + rv = eval_to_string(expr_copy, TRUE); --nested; vim_free(expr_copy); return rv; diff --git a/src/screen.c b/src/screen.c index ea7aaa67f..01d6257b7 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1148,7 +1148,7 @@ get_keymap_str( curwin = wp; STRCPY(buf, "b:keymap_name"); // must be writable ++emsg_skip; - s = p = eval_to_string(buf, NULL, FALSE); + s = p = eval_to_string(buf, FALSE); --emsg_skip; curbuf = old_curbuf; curwin = old_curwin; diff --git a/src/structs.h b/src/structs.h index 0ac486406..395088735 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1753,6 +1753,9 @@ typedef struct { // copied from exarg_T when "getline" is "getsourceline". Can be NULL. void *eval_cookie; // argument for getline() + + // pointer to the line obtained with getsourceline() + char_u *eval_tofree; } evalarg_T; // Flags for expression evaluation. diff --git a/src/userfunc.c b/src/userfunc.c index a27c68d04..c6a8a8cd3 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3716,7 +3716,7 @@ ex_return(exarg_T *eap) eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, &evalarg) != FAIL) + && eval0(arg, &rettv, eap, &evalarg) != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); @@ -3773,7 +3773,7 @@ ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif ++emsg_skip; - if (eval0(eap->arg, &rettv, &eap->nextcmd, NULL) != FAIL) + if (eval0(eap->arg, &rettv, eap, NULL) != FAIL) clear_tv(&rettv); --emsg_skip; return; diff --git a/src/version.c b/src/version.c index 4e2c55379..d39c1b07c 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 */ /**/ + 1049, +/**/ 1048, /**/ 1047, |