mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 9.0.1322: crash when indexing "any" which is an object
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)
This commit is contained in:
@@ -253,6 +253,56 @@ def Test_class_member_initializer()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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()
|
def Test_assignment_with_operator()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@@ -695,6 +695,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 */
|
||||||
|
/**/
|
||||||
|
1322,
|
||||||
/**/
|
/**/
|
||||||
1321,
|
1321,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2011,13 +2011,13 @@ compile_load_lhs(
|
|||||||
size_t varlen = lhs->lhs_varlen;
|
size_t varlen = lhs->lhs_varlen;
|
||||||
int c = var_start[varlen];
|
int c = var_start[varlen];
|
||||||
int lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
|
int lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
|
||||||
char_u *p = var_start;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
// Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and
|
// 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.
|
// limit the lines array length to avoid skipping to a following line.
|
||||||
var_start[varlen] = NUL;
|
var_start[varlen] = NUL;
|
||||||
cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1;
|
cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1;
|
||||||
|
char_u *p = var_start;
|
||||||
res = compile_expr0(&p, cctx);
|
res = compile_expr0(&p, cctx);
|
||||||
var_start[varlen] = c;
|
var_start[varlen] = c;
|
||||||
cctx->ctx_ufunc->uf_lines.ga_len = lines_len;
|
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
|
lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||||
: get_type_on_stack(cctx, 0);
|
: get_type_on_stack(cctx, 0);
|
||||||
// now we can properly check the type
|
// Now we can properly check the type. The variable is indexed, thus
|
||||||
if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL
|
// 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
|
&& 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)
|
-2, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
@@ -2126,9 +2126,13 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
vartype_T dest_type = iptr->isn_arg.storeindex.si_vartype;
|
vartype_T dest_type = iptr->isn_arg.storeindex.si_vartype;
|
||||||
typval_T *tv;
|
typval_T *tv;
|
||||||
typval_T *tv_idx = STACK_TV_BOT(-2);
|
typval_T *tv_idx = STACK_TV_BOT(-2);
|
||||||
|
long lidx = 0;
|
||||||
typval_T *tv_dest = STACK_TV_BOT(-1);
|
typval_T *tv_dest = STACK_TV_BOT(-1);
|
||||||
int status = OK;
|
int status = OK;
|
||||||
|
|
||||||
|
if (tv_idx->v_type == VAR_NUMBER)
|
||||||
|
lidx = (long)tv_idx->vval.v_number;
|
||||||
|
|
||||||
// Stack contains:
|
// Stack contains:
|
||||||
// -3 value to be stored
|
// -3 value to be stored
|
||||||
// -2 index
|
// -2 index
|
||||||
@@ -2140,7 +2144,41 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
dest_type = tv_dest->v_type;
|
dest_type = tv_dest->v_type;
|
||||||
if (dest_type == VAR_DICT)
|
if (dest_type == VAR_DICT)
|
||||||
status = do_2string(tv_idx, TRUE, FALSE);
|
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));
|
emsg(_(e_number_expected));
|
||||||
status = FAIL;
|
status = FAIL;
|
||||||
@@ -2151,7 +2189,6 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
{
|
{
|
||||||
if (dest_type == VAR_LIST)
|
if (dest_type == VAR_LIST)
|
||||||
{
|
{
|
||||||
long lidx = (long)tv_idx->vval.v_number;
|
|
||||||
list_T *list = tv_dest->vval.v_list;
|
list_T *list = tv_dest->vval.v_list;
|
||||||
|
|
||||||
if (list == NULL)
|
if (list == NULL)
|
||||||
@@ -2224,7 +2261,6 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
|
|||||||
}
|
}
|
||||||
else if (dest_type == VAR_BLOB)
|
else if (dest_type == VAR_BLOB)
|
||||||
{
|
{
|
||||||
long lidx = (long)tv_idx->vval.v_number;
|
|
||||||
blob_T *blob = tv_dest->vval.v_blob;
|
blob_T *blob = tv_dest->vval.v_blob;
|
||||||
varnumber_T nr;
|
varnumber_T nr;
|
||||||
int error = FALSE;
|
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)
|
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;
|
object_T *obj = tv_dest->vval.v_object;
|
||||||
typval_T *otv = (typval_T *)(obj + 1);
|
typval_T *otv = (typval_T *)(obj + 1);
|
||||||
|
|
||||||
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
class_T *itf = iptr->isn_arg.storeindex.si_class;
|
||||||
if (itf != NULL)
|
if (itf != NULL)
|
||||||
// convert interface member index to class member index
|
// convert interface member index to class member index
|
||||||
idx = object_index_from_itf_index(itf, FALSE,
|
lidx = object_index_from_itf_index(itf, FALSE,
|
||||||
idx, obj->obj_class);
|
lidx, obj->obj_class);
|
||||||
|
|
||||||
clear_tv(&otv[idx]);
|
clear_tv(&otv[lidx]);
|
||||||
otv[idx] = *tv;
|
otv[lidx] = *tv;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user