forked from aniani/vim
patch 8.2.2131: Vim9: crash when lambda uses same var as assignment
Problem: Vim9: crash when lambda uses same var as assignment. Solution: Do not let lookup_local change lv_from_outer, make a copy. (closes #7461)
This commit is contained in:
@@ -148,45 +148,51 @@ struct cctx_S {
|
||||
static void delete_def_function_contents(dfunc_T *dfunc);
|
||||
|
||||
/*
|
||||
* Lookup variable "name" in the local scope and return it.
|
||||
* Return NULL if not found.
|
||||
* Lookup variable "name" in the local scope and return it in "lvar".
|
||||
* "lvar->lv_from_outer" is set accordingly.
|
||||
* If "lvar" is NULL only check if the variable can be found.
|
||||
* Return FAIL if not found.
|
||||
*/
|
||||
static lvar_T *
|
||||
lookup_local(char_u *name, size_t len, cctx_T *cctx)
|
||||
static int
|
||||
lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
|
||||
{
|
||||
int idx;
|
||||
lvar_T *lvar;
|
||||
lvar_T *lvp;
|
||||
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
return FAIL;
|
||||
|
||||
// Find local in current function scope.
|
||||
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
|
||||
{
|
||||
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
||||
if (STRNCMP(name, lvar->lv_name, len) == 0
|
||||
&& STRLEN(lvar->lv_name) == len)
|
||||
lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
||||
if (STRNCMP(name, lvp->lv_name, len) == 0
|
||||
&& STRLEN(lvp->lv_name) == len)
|
||||
{
|
||||
lvar->lv_from_outer = FALSE;
|
||||
return lvar;
|
||||
if (lvar != NULL)
|
||||
{
|
||||
*lvar = *lvp;
|
||||
lvar->lv_from_outer = FALSE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Find local in outer function scope.
|
||||
if (cctx->ctx_outer != NULL)
|
||||
{
|
||||
lvar = lookup_local(name, len, cctx->ctx_outer);
|
||||
if (lvar != NULL)
|
||||
if (lookup_local(name, len, lvar, cctx->ctx_outer) == OK)
|
||||
{
|
||||
// TODO: are there situations we should not mark the outer scope as
|
||||
// used?
|
||||
cctx->ctx_outer_used = TRUE;
|
||||
lvar->lv_from_outer = TRUE;
|
||||
return lvar;
|
||||
if (lvar != NULL)
|
||||
{
|
||||
cctx->ctx_outer_used = TRUE;
|
||||
lvar->lv_from_outer = TRUE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -377,7 +383,7 @@ check_defined(char_u *p, size_t len, cctx_T *cctx)
|
||||
p[len] = NUL;
|
||||
if (script_var_exists(p, len, FALSE, cctx) == OK
|
||||
|| (cctx != NULL
|
||||
&& (lookup_local(p, len, cctx) != NULL
|
||||
&& (lookup_local(p, len, NULL, cctx) == OK
|
||||
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|
||||
|| find_imported(p, len, cctx) != NULL
|
||||
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
|
||||
@@ -2555,13 +2561,13 @@ compile_load(
|
||||
}
|
||||
else
|
||||
{
|
||||
lvar_T *lvar = lookup_local(*arg, len, cctx);
|
||||
lvar_T lvar;
|
||||
|
||||
if (lvar != NULL)
|
||||
if (lookup_local(*arg, len, &lvar, cctx) == OK)
|
||||
{
|
||||
type = lvar->lv_type;
|
||||
idx = lvar->lv_idx;
|
||||
if (lvar->lv_from_outer)
|
||||
type = lvar.lv_type;
|
||||
idx = lvar.lv_idx;
|
||||
if (lvar.lv_from_outer)
|
||||
gen_load_outer = TRUE;
|
||||
else
|
||||
gen_load = TRUE;
|
||||
@@ -2763,7 +2769,7 @@ compile_call(
|
||||
|
||||
// An argument or local variable can be a function reference, this
|
||||
// overrules a function name.
|
||||
if (lookup_local(namebuf, varlen, cctx) == NULL
|
||||
if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
|
||||
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
|
||||
{
|
||||
// If we can find the function by name generate the right call.
|
||||
@@ -5366,6 +5372,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
assign_dest_T dest = dest_local;
|
||||
int opt_flags = 0;
|
||||
int vimvaridx = -1;
|
||||
lvar_T local_lvar;
|
||||
lvar_T *lvar = NULL;
|
||||
lvar_T arg_lvar;
|
||||
int has_type = FALSE;
|
||||
@@ -5424,8 +5431,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
goto theend;
|
||||
}
|
||||
|
||||
lvar = lookup_local(var_start, varlen, cctx);
|
||||
if (lvar == NULL)
|
||||
|
||||
if (lookup_local(var_start, varlen, &local_lvar, cctx) == OK)
|
||||
lvar = &local_lvar;
|
||||
else
|
||||
{
|
||||
CLEAR_FIELD(arg_lvar);
|
||||
if (arg_exists(var_start, varlen,
|
||||
@@ -6579,8 +6588,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
var_lvar = lookup_local(arg, varlen, cctx);
|
||||
if (var_lvar != NULL)
|
||||
if (lookup_local(arg, varlen, NULL, cctx) == OK)
|
||||
{
|
||||
semsg(_(e_variable_already_declared), arg);
|
||||
goto failed;
|
||||
@@ -7584,7 +7592,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
|| *ea.cmd == '$'
|
||||
|| *ea.cmd == '@'
|
||||
|| ((len) > 2 && ea.cmd[1] == ':')
|
||||
|| lookup_local(ea.cmd, len, &cctx) != NULL
|
||||
|| lookup_local(ea.cmd, len, NULL, &cctx) == OK
|
||||
|| arg_exists(ea.cmd, len, NULL, NULL,
|
||||
NULL, &cctx) == OK
|
||||
|| script_var_exists(ea.cmd, len,
|
||||
@@ -7637,7 +7645,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
}
|
||||
}
|
||||
p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
|
||||
: (void *(*)(char_u *, size_t, cctx_T *))lookup_local,
|
||||
: (int (*)(char_u *, size_t, void *, cctx_T *))lookup_local,
|
||||
&cctx);
|
||||
|
||||
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
|
||||
|
Reference in New Issue
Block a user