diff src/vim9script.c @ 25358:f03271631eb5 v8.2.3216

patch 8.2.3216: Vim9: crash when using variable in a loop at script level Commit: https://github.com/vim/vim/commit/2eb6fc3b52148f961e804ec2be361d531ff770d8 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 25 14:13:53 2021 +0200 patch 8.2.3216: Vim9: crash when using variable in a loop at script level Problem: Vim9: crash when using variable in a loop at script level. Solution: Do not clear the variable if a function was defined. Do not create a new entry in sn_var_vals every time. (closes #8628)
author Bram Moolenaar <Bram@vim.org>
date Sun, 25 Jul 2021 14:15:04 +0200
parents 1e6da8364a02
children 3e56078569ca
line wrap: on
line diff
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -758,47 +758,72 @@ update_vim9_script_var(
 {
     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
     hashitem_T	    *hi;
-    svar_T	    *sv;
+    svar_T	    *sv = NULL;
 
     if (create)
     {
-	sallvar_T	    *newsav;
+	sallvar_T   *newsav;
+	sallvar_T   *sav = NULL;
 
 	// Store a pointer to the typval_T, so that it can be found by index
 	// instead of using a hastab lookup.
 	if (ga_grow(&si->sn_var_vals, 1) == FAIL)
 	    return;
 
-	sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
-	newsav = (sallvar_T *)alloc_clear(
-				       sizeof(sallvar_T) + STRLEN(di->di_key));
-	if (newsav == NULL)
-	    return;
-
-	sv->sv_tv = &di->di_tv;
-	sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
-				   : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
-	sv->sv_export = is_export;
-	newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
-	++si->sn_var_vals.ga_len;
-	STRCPY(&newsav->sav_key, di->di_key);
-	sv->sv_name = newsav->sav_key;
-	newsav->sav_di = di;
-	newsav->sav_block_id = si->sn_current_block_id;
-
-	hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
+	hi = hash_find(&si->sn_all_vars.dv_hashtab, di->di_key);
 	if (!HASHITEM_EMPTY(hi))
 	{
-	    sallvar_T *sav = HI2SAV(hi);
+	    // Variable with this name exists, either in this block or in
+	    // another block.
+	    for (sav = HI2SAV(hi); ; sav = sav->sav_next)
+	    {
+		if (sav->sav_block_id == si->sn_current_block_id)
+		{
+		    // variable defined in a loop, re-use the entry
+		    sv = ((svar_T *)si->sn_var_vals.ga_data)
+						       + sav->sav_var_vals_idx;
+		    // unhide the variable
+		    if (sv->sv_tv == &sav->sav_tv)
+		    {
+			clear_tv(&sav->sav_tv);
+			sv->sv_tv = &di->di_tv;
+			sav->sav_di = di;
+		    }
+		    break;
+		}
+		if (sav->sav_next == NULL)
+		    break;
+	    }
+	}
 
-	    // variable with this name exists in another block
-	    while (sav->sav_next != NULL)
-		sav = sav->sav_next;
-	    sav->sav_next = newsav;
+	if (sv == NULL)
+	{
+	    // Variable not defined or not defined in current block: Add a
+	    // svar_T and create a new sallvar_T.
+	    sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
+	    newsav = (sallvar_T *)alloc_clear(
+				       sizeof(sallvar_T) + STRLEN(di->di_key));
+	    if (newsav == NULL)
+		return;
+
+	    sv->sv_tv = &di->di_tv;
+	    sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
+				   : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
+	    sv->sv_export = is_export;
+	    newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
+	    ++si->sn_var_vals.ga_len;
+	    STRCPY(&newsav->sav_key, di->di_key);
+	    sv->sv_name = newsav->sav_key;
+	    newsav->sav_di = di;
+	    newsav->sav_block_id = si->sn_current_block_id;
+
+	    if (HASHITEM_EMPTY(hi))
+		// new variable name
+		hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
+	    else if (sav != NULL)
+		// existing name in a new block, append to the list
+		sav->sav_next = newsav;
 	}
-	else
-	    // new variable name
-	    hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
     }
     else
     {
@@ -807,8 +832,7 @@ update_vim9_script_var(
     if (sv != NULL)
     {
 	if (*type == NULL)
-	    *type = typval2type(tv, get_copyID(), &si->sn_type_list,
-								    do_member);
+	    *type = typval2type(tv, get_copyID(), &si->sn_type_list, do_member);
 	sv->sv_type = *type;
     }