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:
parent
cc2335896b
commit
709664cca0
@ -2721,19 +2721,23 @@ get_script_local_ht(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for "name[len]" in script-local variables.
|
* Look for "name[len]" in script-local variables.
|
||||||
* Return a non-NULL pointer when found, NULL when not found.
|
* Return OK when found, FAIL when not found.
|
||||||
*/
|
*/
|
||||||
void *
|
int
|
||||||
lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
|
lookup_scriptvar(
|
||||||
|
char_u *name,
|
||||||
|
size_t len,
|
||||||
|
void *lvar UNUSED,
|
||||||
|
cctx_T *dummy UNUSED)
|
||||||
{
|
{
|
||||||
hashtab_T *ht = get_script_local_ht();
|
hashtab_T *ht = get_script_local_ht();
|
||||||
char_u buffer[30];
|
char_u buffer[30];
|
||||||
char_u *p;
|
char_u *p;
|
||||||
void *res;
|
int res;
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
|
|
||||||
if (ht == NULL)
|
if (ht == NULL)
|
||||||
return NULL;
|
return FAIL;
|
||||||
if (len < sizeof(buffer) - 1)
|
if (len < sizeof(buffer) - 1)
|
||||||
{
|
{
|
||||||
// avoid an alloc/free for short names
|
// avoid an alloc/free for short names
|
||||||
@ -2744,20 +2748,19 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
|
|||||||
{
|
{
|
||||||
p = vim_strnsave(name, len);
|
p = vim_strnsave(name, len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hi = hash_find(ht, p);
|
hi = hash_find(ht, p);
|
||||||
res = HASHITEM_EMPTY(hi) ? NULL : hi;
|
res = HASHITEM_EMPTY(hi) ? FAIL : OK;
|
||||||
|
|
||||||
// if not script-local, then perhaps imported
|
// if not script-local, then perhaps imported
|
||||||
if (res == NULL && find_imported(p, 0, NULL) != NULL)
|
if (res == FAIL && find_imported(p, 0, NULL) != NULL)
|
||||||
res = p;
|
res = OK;
|
||||||
|
|
||||||
if (p != buffer)
|
if (p != buffer)
|
||||||
vim_free(p);
|
vim_free(p);
|
||||||
// Don't return "buffer", gcc complains.
|
return res;
|
||||||
return res == NULL ? NULL : IObuff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3271,7 +3271,7 @@ skip_option_env_lead(char_u *start)
|
|||||||
find_ex_command(
|
find_ex_command(
|
||||||
exarg_T *eap,
|
exarg_T *eap,
|
||||||
int *full UNUSED,
|
int *full UNUSED,
|
||||||
void *(*lookup)(char_u *, size_t, cctx_T *) UNUSED,
|
int (*lookup)(char_u *, size_t, void *, cctx_T *) UNUSED,
|
||||||
cctx_T *cctx UNUSED)
|
cctx_T *cctx UNUSED)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@ -3387,7 +3387,7 @@ find_ex_command(
|
|||||||
|| *eap->cmd == '&'
|
|| *eap->cmd == '&'
|
||||||
|| *eap->cmd == '$'
|
|| *eap->cmd == '$'
|
||||||
|| *eap->cmd == '@'
|
|| *eap->cmd == '@'
|
||||||
|| lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
|
|| lookup(eap->cmd, p - eap->cmd, NULL, cctx) == OK)
|
||||||
{
|
{
|
||||||
eap->cmdidx = CMD_var;
|
eap->cmdidx = CMD_var;
|
||||||
return eap->cmd;
|
return eap->cmd;
|
||||||
|
@ -59,7 +59,7 @@ void check_vars(char_u *name, int len);
|
|||||||
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
|
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
|
||||||
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
|
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
|
||||||
hashtab_T *get_script_local_ht(void);
|
hashtab_T *get_script_local_ht(void);
|
||||||
void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
|
int lookup_scriptvar(char_u *name, size_t len, void *lvar, cctx_T *dummy);
|
||||||
hashtab_T *find_var_ht(char_u *name, char_u **varname);
|
hashtab_T *find_var_ht(char_u *name, char_u **varname);
|
||||||
char_u *get_var_value(char_u *name);
|
char_u *get_var_value(char_u *name);
|
||||||
void new_script_vars(scid_T id);
|
void new_script_vars(scid_T id);
|
||||||
|
@ -13,7 +13,7 @@ void undo_cmdmod(cmdmod_T *cmod);
|
|||||||
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
|
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
|
||||||
int checkforcmd(char_u **pp, char *cmd, int len);
|
int checkforcmd(char_u **pp, char *cmd, int len);
|
||||||
char_u *skip_option_env_lead(char_u *start);
|
char_u *skip_option_env_lead(char_u *start);
|
||||||
char_u *find_ex_command(exarg_T *eap, int *full, void *(*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
|
char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, void *, cctx_T *), cctx_T *cctx);
|
||||||
int modifier_len(char_u *cmd);
|
int modifier_len(char_u *cmd);
|
||||||
int cmd_exists(char_u *name);
|
int cmd_exists(char_u *name);
|
||||||
cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
|
cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
|
||||||
|
@ -481,6 +481,12 @@ def Test_call_lambda_args()
|
|||||||
CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
|
CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_lambda_uses_assigned_var()
|
||||||
|
CheckDefSuccess([
|
||||||
|
'var x: any = "aaa"'
|
||||||
|
'x = filter(["bbb"], {_, v -> v =~ x})'])
|
||||||
|
enddef
|
||||||
|
|
||||||
" Default arg and varargs
|
" Default arg and varargs
|
||||||
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
||||||
var res = one .. ',' .. two
|
var res = one .. ',' .. two
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2131,
|
||||||
/**/
|
/**/
|
||||||
2130,
|
2130,
|
||||||
/**/
|
/**/
|
||||||
|
@ -148,45 +148,51 @@ struct cctx_S {
|
|||||||
static void delete_def_function_contents(dfunc_T *dfunc);
|
static void delete_def_function_contents(dfunc_T *dfunc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup variable "name" in the local scope and return it.
|
* Lookup variable "name" in the local scope and return it in "lvar".
|
||||||
* Return NULL if not found.
|
* "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 *
|
static int
|
||||||
lookup_local(char_u *name, size_t len, cctx_T *cctx)
|
lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
lvar_T *lvar;
|
lvar_T *lvp;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return NULL;
|
return FAIL;
|
||||||
|
|
||||||
// Find local in current function scope.
|
// Find local in current function scope.
|
||||||
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
|
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
|
||||||
{
|
{
|
||||||
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
||||||
if (STRNCMP(name, lvar->lv_name, len) == 0
|
if (STRNCMP(name, lvp->lv_name, len) == 0
|
||||||
&& STRLEN(lvar->lv_name) == len)
|
&& STRLEN(lvp->lv_name) == len)
|
||||||
{
|
{
|
||||||
lvar->lv_from_outer = FALSE;
|
if (lvar != NULL)
|
||||||
return lvar;
|
{
|
||||||
|
*lvar = *lvp;
|
||||||
|
lvar->lv_from_outer = FALSE;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find local in outer function scope.
|
// Find local in outer function scope.
|
||||||
if (cctx->ctx_outer != NULL)
|
if (cctx->ctx_outer != NULL)
|
||||||
{
|
{
|
||||||
lvar = lookup_local(name, len, cctx->ctx_outer);
|
if (lookup_local(name, len, lvar, cctx->ctx_outer) == OK)
|
||||||
if (lvar != NULL)
|
|
||||||
{
|
{
|
||||||
// TODO: are there situations we should not mark the outer scope as
|
if (lvar != NULL)
|
||||||
// used?
|
{
|
||||||
cctx->ctx_outer_used = TRUE;
|
cctx->ctx_outer_used = TRUE;
|
||||||
lvar->lv_from_outer = TRUE;
|
lvar->lv_from_outer = TRUE;
|
||||||
return lvar;
|
}
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -377,7 +383,7 @@ check_defined(char_u *p, size_t len, cctx_T *cctx)
|
|||||||
p[len] = NUL;
|
p[len] = NUL;
|
||||||
if (script_var_exists(p, len, FALSE, cctx) == OK
|
if (script_var_exists(p, len, FALSE, cctx) == OK
|
||||||
|| (cctx != NULL
|
|| (cctx != NULL
|
||||||
&& (lookup_local(p, len, cctx) != NULL
|
&& (lookup_local(p, len, NULL, cctx) == OK
|
||||||
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|
||||||
|| find_imported(p, len, cctx) != NULL
|
|| find_imported(p, len, cctx) != NULL
|
||||||
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
|
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
|
||||||
@ -2555,13 +2561,13 @@ compile_load(
|
|||||||
}
|
}
|
||||||
else
|
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;
|
type = lvar.lv_type;
|
||||||
idx = lvar->lv_idx;
|
idx = lvar.lv_idx;
|
||||||
if (lvar->lv_from_outer)
|
if (lvar.lv_from_outer)
|
||||||
gen_load_outer = TRUE;
|
gen_load_outer = TRUE;
|
||||||
else
|
else
|
||||||
gen_load = TRUE;
|
gen_load = TRUE;
|
||||||
@ -2763,7 +2769,7 @@ compile_call(
|
|||||||
|
|
||||||
// An argument or local variable can be a function reference, this
|
// An argument or local variable can be a function reference, this
|
||||||
// overrules a function name.
|
// 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)
|
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
|
||||||
{
|
{
|
||||||
// If we can find the function by name generate the right call.
|
// 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;
|
assign_dest_T dest = dest_local;
|
||||||
int opt_flags = 0;
|
int opt_flags = 0;
|
||||||
int vimvaridx = -1;
|
int vimvaridx = -1;
|
||||||
|
lvar_T local_lvar;
|
||||||
lvar_T *lvar = NULL;
|
lvar_T *lvar = NULL;
|
||||||
lvar_T arg_lvar;
|
lvar_T arg_lvar;
|
||||||
int has_type = FALSE;
|
int has_type = FALSE;
|
||||||
@ -5424,8 +5431,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
goto theend;
|
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);
|
CLEAR_FIELD(arg_lvar);
|
||||||
if (arg_exists(var_start, varlen,
|
if (arg_exists(var_start, varlen,
|
||||||
@ -6579,8 +6588,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var_lvar = lookup_local(arg, varlen, cctx);
|
if (lookup_local(arg, varlen, NULL, cctx) == OK)
|
||||||
if (var_lvar != NULL)
|
|
||||||
{
|
{
|
||||||
semsg(_(e_variable_already_declared), arg);
|
semsg(_(e_variable_already_declared), arg);
|
||||||
goto failed;
|
goto failed;
|
||||||
@ -7584,7 +7592,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
|| *ea.cmd == '$'
|
|| *ea.cmd == '$'
|
||||||
|| *ea.cmd == '@'
|
|| *ea.cmd == '@'
|
||||||
|| ((len) > 2 && ea.cmd[1] == ':')
|
|| ((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,
|
|| arg_exists(ea.cmd, len, NULL, NULL,
|
||||||
NULL, &cctx) == OK
|
NULL, &cctx) == OK
|
||||||
|| script_var_exists(ea.cmd, len,
|
|| 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
|
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);
|
&cctx);
|
||||||
|
|
||||||
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
|
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user