diff src/evalfunc.c @ 19201:e7b4fff348dd v8.2.0159

patch 8.2.0159: non-materialized range() list causes problems Commit: https://github.com/vim/vim/commit/50985eb1f0bd3c73ce727f9bbd66c839c92ef0da Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jan 27 22:09:39 2020 +0100 patch 8.2.0159: non-materialized range() list causes problems Problem: Non-materialized range() list causes problems. (Fujiwara Takuya) Solution: Materialize the list where needed.
author Bram Moolenaar <Bram@vim.org>
date Mon, 27 Jan 2020 22:15:07 +0100
parents 94eda51ba9ba
children d776967d0f0d
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1856,7 +1856,7 @@ f_empty(typval_T *argvars, typval_T *ret
 #endif
 	case VAR_LIST:
 	    n = argvars[0].vval.v_list == NULL
-				  || argvars[0].vval.v_list->lv_first == NULL;
+					|| argvars[0].vval.v_list->lv_len == 0;
 	    break;
 	case VAR_DICT:
 	    n = argvars[0].vval.v_dict == NULL
@@ -2064,7 +2064,7 @@ execute_common(typval_T *argvars, typval
     if (argvars[arg_off].v_type == VAR_LIST)
     {
 	list = argvars[arg_off].vval.v_list;
-	if (list == NULL || list->lv_first == NULL)
+	if (list == NULL || list->lv_len == 0)
 	    // empty list, no commands, empty output
 	    return;
 	++list->lv_refcount;
@@ -2114,8 +2114,10 @@ execute_common(typval_T *argvars, typval
 	do_cmdline_cmd(cmd);
     else
     {
-	listitem_T	*item = list->lv_first;
-
+	listitem_T	*item;
+
+	range_list_materialize(list);
+	item = list->lv_first;
 	do_cmdline(NULL, get_list_line, (void *)&item,
 		      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
 	--list->lv_refcount;
@@ -2643,9 +2645,12 @@ common_function(typval_T *argvars, typva
 		    for (i = 0; i < arg_len; i++)
 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
 		    if (lv_len > 0)
+		    {
+			range_list_materialize(list);
 			for (li = list->lv_first; li != NULL;
 							 li = li->li_next)
 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+		    }
 		}
 
 		// For "function(dict.func, [], dict)" and "func" is a partial
@@ -4058,6 +4063,7 @@ f_index(typval_T *argvars, typval_T *ret
     l = argvars[0].vval.v_list;
     if (l != NULL)
     {
+	range_list_materialize(l);
 	item = l->lv_first;
 	if (argvars[2].v_type != VAR_UNKNOWN)
 	{
@@ -4139,6 +4145,7 @@ f_inputdialog(typval_T *argvars, typval_
     static void
 f_inputlist(typval_T *argvars, typval_T *rettv)
 {
+    list_T	*l;
     listitem_T	*li;
     int		selected;
     int		mouse_used;
@@ -4161,7 +4168,9 @@ f_inputlist(typval_T *argvars, typval_T 
     msg_scroll = TRUE;
     msg_clr_eos();
 
-    for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
+    l = argvars[0].vval.v_list;
+    range_list_materialize(l);
+    for (li = l->lv_first; li != NULL; li = li->li_next)
     {
 	msg_puts((char *)tv_get_string(&li->li_tv));
 	msg_putchar('\n');
@@ -4644,6 +4653,7 @@ find_some_match(typval_T *argvars, typva
     {
 	if ((l = argvars[0].vval.v_list) == NULL)
 	    goto theend;
+	range_list_materialize(l);
 	li = l->lv_first;
     }
     else
@@ -4873,6 +4883,7 @@ max_min(typval_T *argvars, typval_T *ret
 	l = argvars[0].vval.v_list;
 	if (l != NULL)
 	{
+	    range_list_materialize(l);
 	    li = l->lv_first;
 	    if (li != NULL)
 	    {
@@ -5322,7 +5333,7 @@ f_range(typval_T *argvars, typval_T *ret
 	list->lv_start = start;
 	list->lv_end = end;
 	list->lv_stride = stride;
-	list->lv_len = (end - start + 1) / stride;
+	list->lv_len = (end - start) / stride + 1;
     }
 }
 
@@ -6790,22 +6801,25 @@ f_setreg(typval_T *argvars, typval_T *re
 	allocval = lstval + len + 2;
 	curallocval = allocval;
 
-	for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
-							     li = li->li_next)
+	if (ll != NULL)
 	{
-	    strval = tv_get_string_buf_chk(&li->li_tv, buf);
-	    if (strval == NULL)
-		goto free_lstval;
-	    if (strval == buf)
+	    range_list_materialize(ll);
+	    for (li = ll->lv_first; li != NULL; li = li->li_next)
 	    {
-		// Need to make a copy, next tv_get_string_buf_chk() will
-		// overwrite the string.
-		strval = vim_strsave(buf);
+		strval = tv_get_string_buf_chk(&li->li_tv, buf);
 		if (strval == NULL)
 		    goto free_lstval;
-		*curallocval++ = strval;
+		if (strval == buf)
+		{
+		    // Need to make a copy, next tv_get_string_buf_chk() will
+		    // overwrite the string.
+		    strval = vim_strsave(buf);
+		    if (strval == NULL)
+			goto free_lstval;
+		    *curallocval++ = strval;
+		}
+		*curval++ = strval;
 	    }
-	    *curval++ = strval;
 	}
 	*curval++ = NULL;