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 -- Br...@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 ///