diff src/vim9compile.c @ 23171:bb7531f77529 v8.2.2131

patch 8.2.2131: Vim9: crash when lambda uses same var as assignment Commit: https://github.com/vim/vim/commit/709664cca0b59b69caa1ed40ebfcf00b2c672693 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Dec 12 14:33:41 2020 +0100 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 12 Dec 2020 14:45:05 +0100
parents 6aa8ddf7a3fa
children 4d5d12138b36
line wrap: on
line diff
--- 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.
- */
-    static lvar_T *
-lookup_local(char_u *name, size_t len, cctx_T *cctx)
+ * 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 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)
-	{
-	    lvar->lv_from_outer = FALSE;
-	    return lvar;
+	lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
+	if (STRNCMP(name, lvp->lv_name, len) == 0
+					       && STRLEN(lvp->lv_name) == len)
+	{
+	    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)
-	{
-	    // 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;
-	}
-    }
-
-    return NULL;
+	if (lookup_local(name, len, lvar, cctx->ctx_outer) == OK)
+	{
+	    if (lvar != NULL)
+	    {
+		cctx->ctx_outer_used = TRUE;
+		lvar->lv_from_outer = TRUE;
+	    }
+	    return OK;
+	}
+    }
+
+    return FAIL;
 }
 
 /*
@@ -377,7 +383,7 @@ check_defined(char_u *p, size_t len, cct
     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);
-
-	    if (lvar != NULL)
+	    lvar_T lvar;
+
+	    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 
 	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 
 			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 *c
 	}
 	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
 			    || *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
 	    }
 	}
 	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)