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)
diff --git a/src/userfunc.c b/src/userfunc.c
index be1eaa9..7c96347 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -614,6 +614,35 @@
}
/*
+ * 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 @@
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 @@
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 @@
vim_free(tofree2);
if (types_optional)
ga_clear_strings(&argtypes);
+
return OK;
errret:
@@ -4313,28 +4347,8 @@
// 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)
{