]> granicus.if.org Git - vim/commitdiff
patch 9.0.1322: crash when indexing "any" which is an object v9.0.1322
authorBram Moolenaar <Bram@vim.org>
Sat, 18 Feb 2023 18:38:37 +0000 (18:38 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 18 Feb 2023 18:38:37 +0000 (18:38 +0000)
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)

src/testdir/test_vim9_class.vim
src/version.c
src/vim9compile.c
src/vim9execute.c

index 2cd3bdd1b2fac9fbfabfbf4d977dab054bddecc8..d1f361a91971df2820d766cc2a27d50868d7b62a 100644 (file)
@@ -253,6 +253,56 @@ def Test_class_member_initializer()
   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
index 41822fdf48a30af8f5342bc3696765013cbc8de3..214e33a16292a95e7ee6d3ea43128d4dc8a50cd7 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1322,
 /**/
     1321,
 /**/
index 0f002f946b0fdbf80ff54d73347d1a82335cd9b2..628938cba41ba86136089777eddda7ad2254599e 100644 (file)
@@ -2011,13 +2011,13 @@ compile_load_lhs(
        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;
+       char_u *p = var_start;
        res = compile_expr0(&p, cctx);
        var_start[varlen] = c;
        cctx->ctx_ufunc->uf_lines.ga_len = lines_len;
@@ -2031,10 +2031,15 @@ compile_load_lhs(
 
        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
+       // 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, lhs->lhs_type->tt_member, FALSE,
+               && need_type(rhs_type, member_type, FALSE,
                                            -2, 0, cctx, FALSE, FALSE) == FAIL)
            return FAIL;
     }
index 4bbed825940a979c8eee6f9deca9b4a2efe14dc6..638dbc5ca40c4405d89503576faf4dbad5bee20e 100644 (file)
@@ -2126,9 +2126,13 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
     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,7 +2144,41 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
        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)
+       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,7 +2189,6 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
     {
        if (dest_type == VAR_LIST)
        {
-           long            lidx = (long)tv_idx->vval.v_number;
            list_T          *list = tv_dest->vval.v_list;
 
            if (list == NULL)
@@ -2224,7 +2261,6 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
        }
        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;
@@ -2255,18 +2291,17 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
        }
        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);
+               lidx = object_index_from_itf_index(itf, FALSE,
+                                                        lidx, obj->obj_class);
 
-           clear_tv(&otv[idx]);
-           otv[idx] = *tv;
+           clear_tv(&otv[lidx]);
+           otv[lidx] = *tv;
        }
        else
        {