To: vim_dev@googlegroups.com Subject: Patch 8.2.3029 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3029 Problem: Vim9: crash when using operator and list unpack assignment. (Naohiro Ono) Solution: Get variable value before operation. (closes #8416) Files: src/vim9.h, src/vim9compile.c, src/vim9execute.c, src/ex_docmd.c, src/testdir/test_vim9_assign.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.3028/src/vim9.h 2021-06-20 19:28:10.273021391 +0200 --- src/vim9.h 2021-06-21 19:13:53.527023420 +0200 *************** *** 209,214 **** --- 209,220 ---- int cuf_argcount; // number of arguments on top of stack } cufunc_T; + // arguments to ISN_GETITEM + typedef struct { + varnumber_T gi_index; + int gi_with_op; + } getitem_T; + typedef enum { JUMP_ALWAYS, JUMP_IF_FALSE, // pop and jump if false *************** *** 432,437 **** --- 438,444 ---- isn_T *instr; tostring_T tostring; tobool_T tobool; + getitem_T getitem; } isn_arg; }; *** ../vim-8.2.3028/src/vim9compile.c 2021-06-17 21:03:04.038634999 +0200 --- src/vim9compile.c 2021-06-21 19:11:14.315362970 +0200 *************** *** 1240,1252 **** /* * Generate an ISN_GETITEM instruction with "index". */ static int ! generate_GETITEM(cctx_T *cctx, int index) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; type_T *item_type = &t_any; RETURN_OK_IF_SKIP(cctx); --- 1240,1255 ---- /* * Generate an ISN_GETITEM instruction with "index". + * "with_op" is TRUE for "+=" and other operators, the stack has the current + * value below the list with values. */ static int ! generate_GETITEM(cctx_T *cctx, int index, int with_op) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len ! - (with_op ? 2 : 1)]; type_T *item_type = &t_any; RETURN_OK_IF_SKIP(cctx); *************** *** 1260,1266 **** item_type = type->tt_member; if ((isn = generate_instr(cctx, ISN_GETITEM)) == NULL) return FAIL; ! isn->isn_arg.number = index; // add the item type to the type stack if (ga_grow(stack, 1) == FAIL) --- 1263,1270 ---- item_type = type->tt_member; if ((isn = generate_instr(cctx, ISN_GETITEM)) == NULL) return FAIL; ! isn->isn_arg.getitem.gi_index = index; ! isn->isn_arg.getitem.gi_with_op = with_op; // add the item type to the type stack if (ga_grow(stack, 1) == FAIL) *************** *** 6746,6764 **** int is_const = FALSE; char_u *wp; // For "var = expr" evaluate the expression. if (var_count == 0) { int r; - // for "+=", "*=", "..=" etc. first load the current value - if (*op != '=') - { - if (compile_load_lhs_with_index(&lhs, var_start, - cctx) == FAIL) - goto theend; - } - // Compile the expression. instr_count = instr->ga_len; if (incdec) --- 6750,6766 ---- int is_const = FALSE; char_u *wp; + // for "+=", "*=", "..=" etc. first load the current value + if (*op != '=' + && compile_load_lhs_with_index(&lhs, var_start, + cctx) == FAIL) + goto theend; + // For "var = expr" evaluate the expression. if (var_count == 0) { int r; // Compile the expression. instr_count = instr->ga_len; if (incdec) *************** *** 6795,6801 **** { // For "[var, var] = expr" get the "var_idx" item from the // list. ! if (generate_GETITEM(cctx, var_idx) == FAIL) goto theend; } --- 6797,6803 ---- { // For "[var, var] = expr" get the "var_idx" item from the // list. ! if (generate_GETITEM(cctx, var_idx, *op != '=') == FAIL) goto theend; } *** ../vim-8.2.3028/src/vim9execute.c 2021-06-20 20:09:38.590432377 +0200 --- src/vim9execute.c 2021-06-21 19:13:09.167121687 +0200 *************** *** 3832,3843 **** case ISN_GETITEM: { listitem_T *li; ! int index = iptr->isn_arg.number; // Get list item: list is at stack-1, push item. // List type and length is checked for when compiling. ! tv = STACK_TV_BOT(-1); ! li = list_find(tv->vval.v_list, index); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; --- 3832,3843 ---- case ISN_GETITEM: { listitem_T *li; ! getitem_T *gi = &iptr->isn_arg.getitem; // Get list item: list is at stack-1, push item. // List type and length is checked for when compiling. ! tv = STACK_TV_BOT(-1 - gi->gi_with_op); ! li = list_find(tv->vval.v_list, gi->gi_index); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; *************** *** 3846,3852 **** // Useful when used in unpack assignment. Reset at // ISN_DROP. ! ectx->ec_where.wt_index = index + 1; ectx->ec_where.wt_variable = TRUE; } break; --- 3846,3852 ---- // Useful when used in unpack assignment. Reset at // ISN_DROP. ! ectx->ec_where.wt_index = gi->gi_index + 1; ectx->ec_where.wt_variable = TRUE; } break; *************** *** 5376,5383 **** case ISN_ANYSLICE: smsg("%s%4d ANYSLICE", pfx, current); break; case ISN_SLICE: smsg("%s%4d SLICE %lld", pfx, current, iptr->isn_arg.number); break; ! case ISN_GETITEM: smsg("%s%4d ITEM %lld", ! pfx, current, iptr->isn_arg.number); break; case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break; case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current, iptr->isn_arg.string); break; --- 5376,5385 ---- case ISN_ANYSLICE: smsg("%s%4d ANYSLICE", pfx, current); break; case ISN_SLICE: smsg("%s%4d SLICE %lld", pfx, current, iptr->isn_arg.number); break; ! case ISN_GETITEM: smsg("%s%4d ITEM %lld%s", pfx, current, ! iptr->isn_arg.getitem.gi_index, ! iptr->isn_arg.getitem.gi_with_op ? ! " with op" : ""); break; case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break; case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current, iptr->isn_arg.string); break; *** ../vim-8.2.3028/src/ex_docmd.c 2021-06-19 21:38:21.728726296 +0200 --- src/ex_docmd.c 2021-06-21 19:31:00.832345242 +0200 *************** *** 3485,3490 **** --- 3485,3492 ---- // can't be an assignment. if (*eap->cmd == '[') { + char_u *eq; + p = to_name_const_end(eap->cmd); if (p == eap->cmd && *p == '[') { *************** *** 3493,3504 **** p = skip_var_list(eap->cmd, TRUE, &count, &semicolon, TRUE); } ! if (p == NULL || p == eap->cmd || *skipwhite(p) != '=') { eap->cmdidx = CMD_eval; return eap->cmd; } ! if (p > eap->cmd && *skipwhite(p) == '=') { eap->cmdidx = CMD_var; return eap->cmd; --- 3495,3513 ---- p = skip_var_list(eap->cmd, TRUE, &count, &semicolon, TRUE); } ! eq = p; ! if (eq != NULL) ! { ! eq = skipwhite(eq); ! if (vim_strchr((char_u *)"+-*/%", *eq) != NULL) ! ++eq; ! } ! if (p == NULL || p == eap->cmd || *eq != '=') { eap->cmdidx = CMD_eval; return eap->cmd; } ! if (p > eap->cmd && *eq == '=') { eap->cmdidx = CMD_var; return eap->cmd; *** ../vim-8.2.3028/src/testdir/test_vim9_assign.vim 2021-06-17 21:03:04.038634999 +0200 --- src/testdir/test_vim9_assign.vim 2021-06-21 19:37:36.107229255 +0200 *************** *** 283,288 **** --- 283,311 ---- [v1, v2; _] = [1, 2, 3, 4, 5] assert_equal(1, v1) assert_equal(2, v2) + + var a = 1 + var b = 3 + [a, b] += [2, 4] + assert_equal(3, a) + assert_equal(7, b) + + [a, b] -= [1, 2] + assert_equal(2, a) + assert_equal(5, b) + + [a, b] *= [3, 2] + assert_equal(6, a) + assert_equal(10, b) + + [a, b] /= [2, 4] + assert_equal(3, a) + assert_equal(2, b) + + [a, b] = [17, 15] + [a, b] %= [5, 3] + assert_equal(2, a) + assert_equal(0, b) END CheckDefAndScriptSuccess(lines) *** ../vim-8.2.3028/src/testdir/test_vim9_disassemble.vim 2021-06-15 22:13:23.829621578 +0200 --- src/testdir/test_vim9_disassemble.vim 2021-06-21 19:43:03.942335821 +0200 *************** *** 452,457 **** --- 452,488 ---- res) enddef + def s:ListAssignWithOp() + var a = 2 + var b = 3 + [a, b] += [4, 5] + enddef + + def Test_disassemble_list_assign_with_op() + var res = execute('disass s:ListAssignWithOp') + assert_match('\d*_ListAssignWithOp\_s*' .. + 'var a = 2\_s*' .. + '\d STORE 2 in $0\_s*' .. + 'var b = 3\_s*' .. + '\d STORE 3 in $1\_s*' .. + '\[a, b\] += \[4, 5\]\_s*' .. + '\d\+ PUSHNR 4\_s*' .. + '\d\+ PUSHNR 5\_s*' .. + '\d\+ NEWLIST size 2\_s*' .. + '\d\+ CHECKLEN 2\_s*' .. + '\d\+ LOAD $0\_s*' .. + '\d\+ ITEM 0 with op\_s*' .. + '\d\+ OPNR +\_s*' .. + '\d\+ STORE $0\_s*' .. + '\d\+ LOAD $1\_s*' .. + '\d\+ ITEM 1 with op\_s*' .. + '\d\+ OPNR +\_s*' .. + '\d\+ STORE $1\_s*' .. + '\d\+ DROP\_s*' .. + '\d\+ RETURN void', + res) + enddef + def s:ListAdd() var l: list = [] add(l, 123) *** ../vim-8.2.3028/src/version.c 2021-06-21 18:43:46.136307978 +0200 --- src/version.c 2021-06-21 19:09:11.287596313 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3029, /**/ -- How To Keep A Healthy Level Of Insanity: 1. At lunch time, sit in your parked car with sunglasses on and point a hair dryer at passing cars. See if they slow down. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///