]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2131: Vim9: crash when lambda uses same var as assignment v8.2.2131
authorBram Moolenaar <Bram@vim.org>
Sat, 12 Dec 2020 13:33:41 +0000 (14:33 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 12 Dec 2020 13:33:41 +0000 (14:33 +0100)
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)

src/evalvars.c
src/ex_docmd.c
src/proto/evalvars.pro
src/proto/ex_docmd.pro
src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c

index dea56be75facf92233b30dc80ba5a23e40abbe03..9e11578e13c01cfaede3d3f2f225aa517220daed 100644 (file)
@@ -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;
 }
 
 /*
index 0788fa3940f08308fdd1c1aa878797ed086fa691..065a03823224558df896868db107220b664bde60 100644 (file)
@@ -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;
index 39ea33893aebd826b0ab29fab1a5caf387cfb13f..0449ea57aea17eb30e1becf0272713e79e920212 100644 (file)
@@ -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);
index 374d3996b34a2c49cb9ca20b0a0ce2c87836c4cd..46030a5fd54e6f3629c4358de44a530f498366e3 100644 (file)
@@ -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);
index aabc373333da8076794925cd9d980b0c3f8909ac..db7da5e14999e12ed4185c734d325463444559c2 100644 (file)
@@ -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
index 65b2857b047012f18e6601cb91432782cda36034..e4c3c6721bfa5be9b9c88ca1b5cd5d4c6d2a9444 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2131,
 /**/
     2130,
 /**/
index ac8fb846a5250cc6298f113933a4219b55ff0d81..55abecf7e9ac2449d8fa848ec4912f209406acf3 100644 (file)
@@ -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)