mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.4662: no error for using out of range list index
Problem: No error for using out of range list index. Solution: Check list index at script level like in compiled function. (closes #10051)
This commit is contained in:
@@ -1311,7 +1311,8 @@ get_lval(
|
|||||||
|
|
||||||
lp->ll_dict = NULL;
|
lp->ll_dict = NULL;
|
||||||
lp->ll_list = lp->ll_tv->vval.v_list;
|
lp->ll_list = lp->ll_tv->vval.v_list;
|
||||||
lp->ll_li = check_range_index_one(lp->ll_list, &lp->ll_n1, quiet);
|
lp->ll_li = check_range_index_one(lp->ll_list, &lp->ll_n1,
|
||||||
|
(flags & GLV_ASSIGN_WITH_OP) == 0, quiet);
|
||||||
if (lp->ll_li == NULL)
|
if (lp->ll_li == NULL)
|
||||||
{
|
{
|
||||||
clear_tv(&var2);
|
clear_tv(&var2);
|
||||||
|
@@ -1647,13 +1647,15 @@ ex_let_one(
|
|||||||
{
|
{
|
||||||
lval_T lv;
|
lval_T lv;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
int lval_flags = (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
|
||||||
|
? GLV_NO_DECL : 0;
|
||||||
|
if (op != NULL && *op != '=')
|
||||||
|
lval_flags |= GLV_ASSIGN_WITH_OP;
|
||||||
|
|
||||||
// ":let var = expr": Set internal variable.
|
// ":let var = expr": Set internal variable.
|
||||||
// ":let var: type = expr": Set internal variable with type.
|
// ":let var: type = expr": Set internal variable with type.
|
||||||
// ":let {expr} = expr": Idem, name made with curly braces
|
// ":let {expr} = expr": Idem, name made with curly braces
|
||||||
p = get_lval(arg, tv, &lv, FALSE, FALSE,
|
p = get_lval(arg, tv, &lv, FALSE, FALSE, lval_flags, FNE_CHECK_START);
|
||||||
(flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
|
|
||||||
? GLV_NO_DECL : 0, FNE_CHECK_START);
|
|
||||||
if (p != NULL && lv.ll_name != NULL)
|
if (p != NULL && lv.ll_name != NULL)
|
||||||
{
|
{
|
||||||
if (endchars != NULL && vim_strchr(endchars,
|
if (endchars != NULL && vim_strchr(endchars,
|
||||||
|
10
src/list.c
10
src/list.c
@@ -760,18 +760,20 @@ list_insert(list_T *l, listitem_T *ni, listitem_T *item)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the list item in "l" with index "n1". "n1" is adjusted if needed.
|
* Get the list item in "l" with index "n1". "n1" is adjusted if needed.
|
||||||
* In Vim9, it is at the end of the list, add an item.
|
* In Vim9, it is at the end of the list, add an item if "can_append" is TRUE.
|
||||||
* Return NULL if there is no such item.
|
* Return NULL if there is no such item.
|
||||||
*/
|
*/
|
||||||
listitem_T *
|
listitem_T *
|
||||||
check_range_index_one(list_T *l, long *n1, int quiet)
|
check_range_index_one(list_T *l, long *n1, int can_append, int quiet)
|
||||||
{
|
{
|
||||||
|
long orig_n1 = *n1;
|
||||||
listitem_T *li = list_find_index(l, n1);
|
listitem_T *li = list_find_index(l, n1);
|
||||||
|
|
||||||
if (li == NULL)
|
if (li == NULL)
|
||||||
{
|
{
|
||||||
// Vim9: Allow for adding an item at the end.
|
// Vim9: Allow for adding an item at the end.
|
||||||
if (in_vim9script() && *n1 == l->lv_len && l->lv_lock == 0)
|
if (can_append && in_vim9script()
|
||||||
|
&& *n1 == l->lv_len && l->lv_lock == 0)
|
||||||
{
|
{
|
||||||
list_append_number(l, 0);
|
list_append_number(l, 0);
|
||||||
li = list_find_index(l, n1);
|
li = list_find_index(l, n1);
|
||||||
@@ -779,7 +781,7 @@ check_range_index_one(list_T *l, long *n1, int quiet)
|
|||||||
if (li == NULL)
|
if (li == NULL)
|
||||||
{
|
{
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
semsg(_(e_list_index_out_of_range_nr), *n1);
|
semsg(_(e_list_index_out_of_range_nr), orig_n1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ int list_append_string(list_T *l, char_u *str, int len);
|
|||||||
int list_append_number(list_T *l, varnumber_T n);
|
int list_append_number(list_T *l, varnumber_T n);
|
||||||
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
|
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
|
||||||
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
|
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
|
||||||
listitem_T *check_range_index_one(list_T *l, long *n1, int quiet);
|
listitem_T *check_range_index_one(list_T *l, long *n1, int can_append, int quiet);
|
||||||
int check_range_index_two(list_T *l, long *n1, listitem_T *li1, long *n2, int quiet);
|
int check_range_index_two(list_T *l, long *n1, listitem_T *li1, long *n2, int quiet);
|
||||||
int list_assign_range(list_T *dest, list_T *src, long idx1_arg, long idx2, int empty_idx2, char_u *op, char_u *varname);
|
int list_assign_range(list_T *dest, list_T *src, long idx1_arg, long idx2, int empty_idx2, char_u *op, char_u *varname);
|
||||||
void f_flatten(typval_T *argvars, typval_T *rettv);
|
void f_flatten(typval_T *argvars, typval_T *rettv);
|
||||||
|
@@ -288,6 +288,12 @@ def Test_assign_concat()
|
|||||||
s ..= {a: 2}
|
s ..= {a: 2}
|
||||||
END
|
END
|
||||||
v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2)
|
v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var ls: list<string> = []
|
||||||
|
ls[-1] ..= 'foo'
|
||||||
|
END
|
||||||
|
v9.CheckDefExecAndScriptFailure(lines, 'E684: list index out of range: -1', 2)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_assign_register()
|
def Test_assign_register()
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
4662,
|
||||||
/**/
|
/**/
|
||||||
4661,
|
4661,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2632,6 +2632,7 @@ typedef enum {
|
|||||||
#define TFN_NO_DECL 0x20 // only used for GLV_NO_DECL
|
#define TFN_NO_DECL 0x20 // only used for GLV_NO_DECL
|
||||||
#define TFN_COMPILING 0x40 // only used for GLV_COMPILING
|
#define TFN_COMPILING 0x40 // only used for GLV_COMPILING
|
||||||
#define TFN_NEW_FUNC 0x80 // defining a new function
|
#define TFN_NEW_FUNC 0x80 // defining a new function
|
||||||
|
#define TFN_ASSIGN_WITH_OP 0x100 // only for GLV_ASSIGN_WITH_OP
|
||||||
|
|
||||||
// Values for get_lval() flags argument:
|
// Values for get_lval() flags argument:
|
||||||
#define GLV_QUIET TFN_QUIET // no error messages
|
#define GLV_QUIET TFN_QUIET // no error messages
|
||||||
@@ -2639,6 +2640,7 @@ typedef enum {
|
|||||||
#define GLV_READ_ONLY TFN_READ_ONLY // will not change the var
|
#define GLV_READ_ONLY TFN_READ_ONLY // will not change the var
|
||||||
#define GLV_NO_DECL TFN_NO_DECL // assignment without :var or :let
|
#define GLV_NO_DECL TFN_NO_DECL // assignment without :var or :let
|
||||||
#define GLV_COMPILING TFN_COMPILING // variable may be defined later
|
#define GLV_COMPILING TFN_COMPILING // variable may be defined later
|
||||||
|
#define GLV_ASSIGN_WITH_OP TFN_ASSIGN_WITH_OP // assignment with operator
|
||||||
|
|
||||||
#define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
|
#define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
|
||||||
// be freed.
|
// be freed.
|
||||||
|
@@ -1988,7 +1988,7 @@ execute_storerange(isn_T *iptr, ectx_T *ectx)
|
|||||||
else
|
else
|
||||||
n2 = (long)tv_get_number_chk(tv_idx2, NULL);
|
n2 = (long)tv_get_number_chk(tv_idx2, NULL);
|
||||||
|
|
||||||
li1 = check_range_index_one(tv_dest->vval.v_list, &n1, FALSE);
|
li1 = check_range_index_one(tv_dest->vval.v_list, &n1, TRUE, FALSE);
|
||||||
if (li1 == NULL)
|
if (li1 == NULL)
|
||||||
status = FAIL;
|
status = FAIL;
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user