Mercurial > vim
diff src/userfunc.c @ 25358:f03271631eb5 v8.2.3216
patch 8.2.3216: Vim9: crash when using variable in a loop at script level
Commit: https://github.com/vim/vim/commit/2eb6fc3b52148f961e804ec2be361d531ff770d8
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jul 25 14:13:53 2021 +0200
patch 8.2.3216: Vim9: crash when using variable in a loop at script level
Problem: Vim9: crash when using variable in a loop at script level.
Solution: Do not clear the variable if a function was defined.
Do not create a new entry in sn_var_vals every time.
(closes #8628)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 25 Jul 2021 14:15:04 +0200 |
parents | 078edc1821bf |
children | 8ecd3575bc8c |
line wrap: on
line diff
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -614,6 +614,35 @@ is_function_cmd(char_u **cmd) } /* + * Called when defining a function: The context may be needed for script + * variables declared in a block that is visible now but not when the function + * is compiled or called later. + */ + static void +function_using_block_scopes(ufunc_T *fp, cstack_T *cstack) +{ + if (cstack != NULL && cstack->cs_idx >= 0) + { + int count = cstack->cs_idx + 1; + int i; + + fp->uf_block_ids = ALLOC_MULT(int, count); + if (fp->uf_block_ids != NULL) + { + mch_memmove(fp->uf_block_ids, cstack->cs_block_id, + sizeof(int) * count); + fp->uf_block_depth = count; + } + + // Set flag in each block to indicate a function was defined. This + // is used to keep the variable when leaving the block, see + // hide_script_var(). + for (i = 0; i <= cstack->cs_idx; ++i) + cstack->cs_flags[i] |= CSF_FUNC_DEF; + } +} + +/* * Read the body of a function, put every line in "newlines". * This stops at "}", "endfunction" or "enddef". * "newlines" must already have been initialized. @@ -1195,6 +1224,8 @@ lambda_function_body( ufunc->uf_script_ctx.sc_lnum += sourcing_lnum_top; set_function_type(ufunc); + function_using_block_scopes(ufunc, evalarg->eval_cstack); + rettv->vval.v_partial = pt; rettv->v_type = VAR_PARTIAL; ufunc = NULL; @@ -1442,6 +1473,8 @@ get_lambda_tv( fp->uf_script_ctx = current_sctx; fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len; + function_using_block_scopes(fp, evalarg->eval_cstack); + pt->pt_func = fp; pt->pt_refcount = 1; rettv->vval.v_partial = pt; @@ -1459,6 +1492,7 @@ theend: vim_free(tofree2); if (types_optional) ga_clear_strings(&argtypes); + return OK; errret: @@ -4313,28 +4347,8 @@ define_function(exarg_T *eap, char_u *na // error messages are for the first function line SOURCING_LNUM = sourcing_lnum_top; - if (cstack != NULL && cstack->cs_idx >= 0) - { - int count = cstack->cs_idx + 1; - int i; - - // The block context may be needed for script variables declared in - // a block that is visible now but not when the function is called - // later. - fp->uf_block_ids = ALLOC_MULT(int, count); - if (fp->uf_block_ids != NULL) - { - mch_memmove(fp->uf_block_ids, cstack->cs_block_id, - sizeof(int) * count); - fp->uf_block_depth = count; - } - - // Set flag in each block to indicate a function was defined. This - // is used to keep the variable when leaving the block, see - // hide_script_var(). - for (i = 0; i <= cstack->cs_idx; ++i) - cstack->cs_flags[i] |= CSF_FUNC_DEF; - } + // The function may use script variables from the context. + function_using_block_scopes(fp, cstack); if (parse_argument_types(fp, &argtypes, varargs) == FAIL) {