summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-12 14:33:41 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-12 14:33:41 +0100
commit709664cca0b59b69caa1ed40ebfcf00b2c672693 (patch)
tree02c10d1f930402aee6e1dd3d554e35cc0935be4d
parentcc2335896ba707bf0d8cf03cca2de7c66fab62a0 (diff)
patch 8.2.2131: Vim9: crash when lambda uses same var as assignmentv8.2.2131
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)
-rw-r--r--src/evalvars.c25
-rw-r--r--src/ex_docmd.c4
-rw-r--r--src/proto/evalvars.pro2
-rw-r--r--src/proto/ex_docmd.pro2
-rw-r--r--src/testdir/test_vim9_func.vim6
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c72
7 files changed, 66 insertions, 47 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index dea56be75f..9e11578e13 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -2721,19 +2721,23 @@ get_script_local_ht(void)
/*
* 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 *
-lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
+ int
+lookup_scriptvar(
+ char_u *name,
+ size_t len,
+ void *lvar UNUSED,
+ cctx_T *dummy UNUSED)
{
hashtab_T *ht = get_script_local_ht();
char_u buffer[30];
char_u *p;
- void *res;
+ int res;
hashitem_T *hi;
if (ht == NULL)
- return NULL;
+ return FAIL;
if (len < sizeof(buffer) - 1)
{
// 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);
if (p == NULL)
- return NULL;
+ return FAIL;
}
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 (res == NULL && find_imported(p, 0, NULL) != NULL)
- res = p;
+ if (res == FAIL && find_imported(p, 0, NULL) != NULL)
+ res = OK;
if (p != buffer)
vim_free(p);
- // Don't return "buffer", gcc complains.
- return res == NULL ? NULL : IObuff;
+ return res;
}
/*
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0788fa3940..065a038232 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3271,7 +3271,7 @@ skip_option_env_lead(char_u *start)
find_ex_command(
exarg_T *eap,
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)
{
int len;
@@ -3387,7 +3387,7 @@ find_ex_command(
|| *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;
return eap->cmd;
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 39ea33893a..0449ea57ae 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -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_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
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);
char_u *get_var_value(char_u *name);
void new_script_vars(scid_T id);
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index 374d3996b3..46030a5fd5 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -13,7 +13,7 @@ void undo_cmdmod(cmdmod_T *cmod);
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
int checkforcmd(char_u **pp, char *cmd, int len);
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 cmd_exists(char_u *name);
cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index aabc373333..db7da5e149 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -481,6 +481,12 @@ def Test_call_lambda_args()
CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
+def Test_lambda_uses_assigned_var()
+ CheckDefSuccess([
+ 'var x: any = "aaa"'
+ 'x = filter(["bbb"], {_, v -> v =~ x})'])
+enddef
+
" Default arg and varargs
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
var res = one .. ',' .. two
diff --git a/src/version.c b/src/version.c
index 65b2857b04..e4c3c6721b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2131,
+/**/
2130,
/**/
2129,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index ac8fb846a5..55abecf7e9 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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)