To: vim_dev@googlegroups.com Subject: Patch 9.0.1322 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1322 Problem: Crash when indexing "any" which is an object. Solution: Check the index is a number. Do not check the member type of an object. (closes #12019) Files: src/vim9execute.c, src/vim9compile.c, src/testdir/test_vim9_class.vim *** ../vim-9.0.1321/src/vim9execute.c 2023-02-18 14:42:40.117005581 +0000 --- src/vim9execute.c 2023-02-18 17:34:54.853153029 +0000 *************** *** 2126,2134 **** --- 2126,2138 ---- vartype_T dest_type = iptr->isn_arg.storeindex.si_vartype; typval_T *tv; typval_T *tv_idx = STACK_TV_BOT(-2); + long lidx = 0; typval_T *tv_dest = STACK_TV_BOT(-1); int status = OK; + if (tv_idx->v_type == VAR_NUMBER) + lidx = (long)tv_idx->vval.v_number; + // Stack contains: // -3 value to be stored // -2 index *************** *** 2140,2146 **** dest_type = tv_dest->v_type; if (dest_type == VAR_DICT) status = do_2string(tv_idx, TRUE, FALSE); ! else if (dest_type == VAR_LIST && tv_idx->v_type != VAR_NUMBER) { emsg(_(e_number_expected)); status = FAIL; --- 2144,2184 ---- dest_type = tv_dest->v_type; if (dest_type == VAR_DICT) status = do_2string(tv_idx, TRUE, FALSE); ! else if (dest_type == VAR_OBJECT && tv_idx->v_type == VAR_STRING) ! { ! // Need to get the member index now that the class is known. ! object_T *obj = tv_dest->vval.v_object; ! class_T *cl = obj->obj_class; ! char_u *member = tv_idx->vval.v_string; ! ! ocmember_T *m = NULL; ! for (int i = 0; i < cl->class_obj_member_count; ++i) ! { ! m = &cl->class_obj_members[i]; ! if (STRCMP(member, m->ocm_name) == 0) ! { ! if (*member == '_') ! { ! semsg(_(e_cannot_access_private_member_str), ! m->ocm_name); ! status = FAIL; ! } ! ! lidx = i; ! break; ! } ! m = NULL; ! } ! ! if (m == NULL) ! { ! semsg(_(e_member_not_found_on_object_str_str), ! cl->class_name, member); ! status = FAIL; ! } ! } ! else if ((dest_type == VAR_LIST || dest_type == VAR_OBJECT) ! && tv_idx->v_type != VAR_NUMBER) { emsg(_(e_number_expected)); status = FAIL; *************** *** 2151,2157 **** { if (dest_type == VAR_LIST) { - long lidx = (long)tv_idx->vval.v_number; list_T *list = tv_dest->vval.v_list; if (list == NULL) --- 2189,2194 ---- *************** *** 2224,2230 **** } else if (dest_type == VAR_BLOB) { - long lidx = (long)tv_idx->vval.v_number; blob_T *blob = tv_dest->vval.v_blob; varnumber_T nr; int error = FALSE; --- 2261,2266 ---- *************** *** 2255,2272 **** } else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT) { - long idx = (long)tv_idx->vval.v_number; object_T *obj = tv_dest->vval.v_object; typval_T *otv = (typval_T *)(obj + 1); class_T *itf = iptr->isn_arg.storeindex.si_class; if (itf != NULL) // convert interface member index to class member index ! idx = object_index_from_itf_index(itf, FALSE, ! idx, obj->obj_class); ! clear_tv(&otv[idx]); ! otv[idx] = *tv; } else { --- 2291,2307 ---- } else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT) { object_T *obj = tv_dest->vval.v_object; typval_T *otv = (typval_T *)(obj + 1); class_T *itf = iptr->isn_arg.storeindex.si_class; if (itf != NULL) // convert interface member index to class member index ! lidx = object_index_from_itf_index(itf, FALSE, ! lidx, obj->obj_class); ! clear_tv(&otv[lidx]); ! otv[lidx] = *tv; } else { *** ../vim-9.0.1321/src/vim9compile.c 2023-02-08 20:55:23.932100744 +0000 --- src/vim9compile.c 2023-02-18 18:34:34.787068740 +0000 *************** *** 2011,2023 **** size_t varlen = lhs->lhs_varlen; int c = var_start[varlen]; int lines_len = cctx->ctx_ufunc->uf_lines.ga_len; - char_u *p = var_start; int res; // Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and // limit the lines array length to avoid skipping to a following line. var_start[varlen] = NUL; cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1; res = compile_expr0(&p, cctx); var_start[varlen] = c; cctx->ctx_ufunc->uf_lines.ga_len = lines_len; --- 2011,2023 ---- size_t varlen = lhs->lhs_varlen; int c = var_start[varlen]; int lines_len = cctx->ctx_ufunc->uf_lines.ga_len; int res; // Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and // limit the lines array length to avoid skipping to a following line. var_start[varlen] = NUL; cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1; + char_u *p = var_start; res = compile_expr0(&p, cctx); var_start[varlen] = c; cctx->ctx_ufunc->uf_lines.ga_len = lines_len; *************** *** 2031,2040 **** lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void : get_type_on_stack(cctx, 0); ! // now we can properly check the type ! if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL && rhs_type != &t_void ! && need_type(rhs_type, lhs->lhs_type->tt_member, FALSE, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; } --- 2031,2045 ---- lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void : get_type_on_stack(cctx, 0); ! // Now we can properly check the type. The variable is indexed, thus ! // we need the member type. For a class or object we don't know the ! // type yet, it depends on what member is used. ! vartype_T vartype = lhs->lhs_type->tt_type; ! type_T *member_type = lhs->lhs_type->tt_member; ! if (rhs_type != NULL && member_type != NULL ! && vartype != VAR_OBJECT && vartype != VAR_CLASS && rhs_type != &t_void ! && need_type(rhs_type, member_type, FALSE, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; } *** ../vim-9.0.1321/src/testdir/test_vim9_class.vim 2023-02-18 14:42:40.117005581 +0000 --- src/testdir/test_vim9_class.vim 2023-02-18 17:38:44.469231743 +0000 *************** *** 253,258 **** --- 253,308 ---- v9.CheckScriptSuccess(lines) enddef + def Test_member_any_used_as_object() + var lines =<< trim END + vim9script + + class Inner + this.value: number = 0 + endclass + + class Outer + this.inner: any + endclass + + def F(outer: Outer) + outer.inner.value = 1 + enddef + + var inner_obj = Inner.new(0) + var outer_obj = Outer.new(inner_obj) + F(outer_obj) + assert_equal(1, inner_obj.value) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + class Inner + this.value: number = 0 + endclass + + class Outer + this.inner: Inner + endclass + + def F(outer: Outer) + outer.inner.value = 1 + enddef + + def Test_assign_to_nested_typed_member() + var inner = Inner.new(0) + var outer = Outer.new(inner) + F(outer) + assert_equal(1, inner.value) + enddef + + Test_assign_to_nested_typed_member() + END + v9.CheckScriptSuccess(lines) + enddef + def Test_assignment_with_operator() var lines =<< trim END vim9script *** ../vim-9.0.1321/src/version.c 2023-02-18 15:31:49.134360548 +0000 --- src/version.c 2023-02-18 17:13:26.115323294 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1322, /**/ -- Fingers not found - Pound head on keyboard to continue. /// 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 ///