Skip to content

Commit 709664c

Browse files
committed
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)
1 parent cc23358 commit 709664c

7 files changed

Lines changed: 66 additions & 47 deletions

File tree

src/evalvars.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,19 +2721,23 @@ get_script_local_ht(void)
27212721

27222722
/*
27232723
* Look for "name[len]" in script-local variables.
2724-
* Return a non-NULL pointer when found, NULL when not found.
2724+
* Return OK when found, FAIL when not found.
27252725
*/
2726-
void *
2727-
lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
2726+
int
2727+
lookup_scriptvar(
2728+
char_u *name,
2729+
size_t len,
2730+
void *lvar UNUSED,
2731+
cctx_T *dummy UNUSED)
27282732
{
27292733
hashtab_T *ht = get_script_local_ht();
27302734
char_u buffer[30];
27312735
char_u *p;
2732-
void *res;
2736+
int res;
27332737
hashitem_T *hi;
27342738

27352739
if (ht == NULL)
2736-
return NULL;
2740+
return FAIL;
27372741
if (len < sizeof(buffer) - 1)
27382742
{
27392743
// avoid an alloc/free for short names
@@ -2744,20 +2748,19 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
27442748
{
27452749
p = vim_strnsave(name, len);
27462750
if (p == NULL)
2747-
return NULL;
2751+
return FAIL;
27482752
}
27492753

27502754
hi = hash_find(ht, p);
2751-
res = HASHITEM_EMPTY(hi) ? NULL : hi;
2755+
res = HASHITEM_EMPTY(hi) ? FAIL : OK;
27522756

27532757
// if not script-local, then perhaps imported
2754-
if (res == NULL && find_imported(p, 0, NULL) != NULL)
2755-
res = p;
2758+
if (res == FAIL && find_imported(p, 0, NULL) != NULL)
2759+
res = OK;
27562760

27572761
if (p != buffer)
27582762
vim_free(p);
2759-
// Don't return "buffer", gcc complains.
2760-
return res == NULL ? NULL : IObuff;
2763+
return res;
27612764
}
27622765

27632766
/*

src/ex_docmd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3271,7 +3271,7 @@ skip_option_env_lead(char_u *start)
32713271
find_ex_command(
32723272
exarg_T *eap,
32733273
int *full UNUSED,
3274-
void *(*lookup)(char_u *, size_t, cctx_T *) UNUSED,
3274+
int (*lookup)(char_u *, size_t, void *, cctx_T *) UNUSED,
32753275
cctx_T *cctx UNUSED)
32763276
{
32773277
int len;
@@ -3387,7 +3387,7 @@ find_ex_command(
33873387
|| *eap->cmd == '&'
33883388
|| *eap->cmd == '$'
33893389
|| *eap->cmd == '@'
3390-
|| lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
3390+
|| lookup(eap->cmd, p - eap->cmd, NULL, cctx) == OK)
33913391
{
33923392
eap->cmdidx = CMD_var;
33933393
return eap->cmd;

src/proto/evalvars.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void check_vars(char_u *name, int len);
5959
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
6060
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
6161
hashtab_T *get_script_local_ht(void);
62-
void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
62+
int lookup_scriptvar(char_u *name, size_t len, void *lvar, cctx_T *dummy);
6363
hashtab_T *find_var_ht(char_u *name, char_u **varname);
6464
char_u *get_var_value(char_u *name);
6565
void new_script_vars(scid_T id);

src/proto/ex_docmd.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ void undo_cmdmod(cmdmod_T *cmod);
1313
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
1414
int checkforcmd(char_u **pp, char *cmd, int len);
1515
char_u *skip_option_env_lead(char_u *start);
16-
char_u *find_ex_command(exarg_T *eap, int *full, void *(*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
16+
char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, void *, cctx_T *), cctx_T *cctx);
1717
int modifier_len(char_u *cmd);
1818
int cmd_exists(char_u *name);
1919
cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);

src/testdir/test_vim9_func.vim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,12 @@ def Test_call_lambda_args()
481481
CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string')
482482
enddef
483483

484+
def Test_lambda_uses_assigned_var()
485+
CheckDefSuccess([
486+
'var x: any = "aaa"'
487+
'x = filter(["bbb"], {_, v -> v =~ x})'])
488+
enddef
489+
484490
" Default arg and varargs
485491
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
486492
var res = one .. ',' .. two

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2131,
753755
/**/
754756
2130,
755757
/**/

src/vim9compile.c

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -148,45 +148,51 @@ struct cctx_S {
148148
static void delete_def_function_contents(dfunc_T *dfunc);
149149

150150
/*
151-
* Lookup variable "name" in the local scope and return it.
152-
* Return NULL if not found.
151+
* Lookup variable "name" in the local scope and return it in "lvar".
152+
* "lvar->lv_from_outer" is set accordingly.
153+
* If "lvar" is NULL only check if the variable can be found.
154+
* Return FAIL if not found.
153155
*/
154-
static lvar_T *
155-
lookup_local(char_u *name, size_t len, cctx_T *cctx)
156+
static int
157+
lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
156158
{
157159
int idx;
158-
lvar_T *lvar;
160+
lvar_T *lvp;
159161

160162
if (len == 0)
161-
return NULL;
163+
return FAIL;
162164

163165
// Find local in current function scope.
164166
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
165167
{
166-
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
167-
if (STRNCMP(name, lvar->lv_name, len) == 0
168-
&& STRLEN(lvar->lv_name) == len)
168+
lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
169+
if (STRNCMP(name, lvp->lv_name, len) == 0
170+
&& STRLEN(lvp->lv_name) == len)
169171
{
170-
lvar->lv_from_outer = FALSE;
171-
return lvar;
172+
if (lvar != NULL)
173+
{
174+
*lvar = *lvp;
175+
lvar->lv_from_outer = FALSE;
176+
}
177+
return OK;
172178
}
173179
}
174180

175181
// Find local in outer function scope.
176182
if (cctx->ctx_outer != NULL)
177183
{
178-
lvar = lookup_local(name, len, cctx->ctx_outer);
179-
if (lvar != NULL)
184+
if (lookup_local(name, len, lvar, cctx->ctx_outer) == OK)
180185
{
181-
// TODO: are there situations we should not mark the outer scope as
182-
// used?
183-
cctx->ctx_outer_used = TRUE;
184-
lvar->lv_from_outer = TRUE;
185-
return lvar;
186+
if (lvar != NULL)
187+
{
188+
cctx->ctx_outer_used = TRUE;
189+
lvar->lv_from_outer = TRUE;
190+
}
191+
return OK;
186192
}
187193
}
188194

189-
return NULL;
195+
return FAIL;
190196
}
191197

192198
/*
@@ -377,7 +383,7 @@ check_defined(char_u *p, size_t len, cctx_T *cctx)
377383
p[len] = NUL;
378384
if (script_var_exists(p, len, FALSE, cctx) == OK
379385
|| (cctx != NULL
380-
&& (lookup_local(p, len, cctx) != NULL
386+
&& (lookup_local(p, len, NULL, cctx) == OK
381387
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
382388
|| find_imported(p, len, cctx) != NULL
383389
|| (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
@@ -2555,13 +2561,13 @@ compile_load(
25552561
}
25562562
else
25572563
{
2558-
lvar_T *lvar = lookup_local(*arg, len, cctx);
2564+
lvar_T lvar;
25592565

2560-
if (lvar != NULL)
2566+
if (lookup_local(*arg, len, &lvar, cctx) == OK)
25612567
{
2562-
type = lvar->lv_type;
2563-
idx = lvar->lv_idx;
2564-
if (lvar->lv_from_outer)
2568+
type = lvar.lv_type;
2569+
idx = lvar.lv_idx;
2570+
if (lvar.lv_from_outer)
25652571
gen_load_outer = TRUE;
25662572
else
25672573
gen_load = TRUE;
@@ -2763,7 +2769,7 @@ compile_call(
27632769

27642770
// An argument or local variable can be a function reference, this
27652771
// overrules a function name.
2766-
if (lookup_local(namebuf, varlen, cctx) == NULL
2772+
if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
27672773
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
27682774
{
27692775
// 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)
53665372
assign_dest_T dest = dest_local;
53675373
int opt_flags = 0;
53685374
int vimvaridx = -1;
5375+
lvar_T local_lvar;
53695376
lvar_T *lvar = NULL;
53705377
lvar_T arg_lvar;
53715378
int has_type = FALSE;
@@ -5424,8 +5431,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
54245431
goto theend;
54255432
}
54265433

5427-
lvar = lookup_local(var_start, varlen, cctx);
5428-
if (lvar == NULL)
5434+
5435+
if (lookup_local(var_start, varlen, &local_lvar, cctx) == OK)
5436+
lvar = &local_lvar;
5437+
else
54295438
{
54305439
CLEAR_FIELD(arg_lvar);
54315440
if (arg_exists(var_start, varlen,
@@ -6579,8 +6588,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
65796588
}
65806589
else
65816590
{
6582-
var_lvar = lookup_local(arg, varlen, cctx);
6583-
if (var_lvar != NULL)
6591+
if (lookup_local(arg, varlen, NULL, cctx) == OK)
65846592
{
65856593
semsg(_(e_variable_already_declared), arg);
65866594
goto failed;
@@ -7584,7 +7592,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
75847592
|| *ea.cmd == '$'
75857593
|| *ea.cmd == '@'
75867594
|| ((len) > 2 && ea.cmd[1] == ':')
7587-
|| lookup_local(ea.cmd, len, &cctx) != NULL
7595+
|| lookup_local(ea.cmd, len, NULL, &cctx) == OK
75887596
|| arg_exists(ea.cmd, len, NULL, NULL,
75897597
NULL, &cctx) == OK
75907598
|| script_var_exists(ea.cmd, len,
@@ -7637,7 +7645,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
76377645
}
76387646
}
76397647
p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
7640-
: (void *(*)(char_u *, size_t, cctx_T *))lookup_local,
7648+
: (int (*)(char_u *, size_t, void *, cctx_T *))lookup_local,
76417649
&cctx);
76427650

76437651
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)

0 commit comments

Comments
 (0)