summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2024-07-26 18:37:02 +0200
committerChristian Brabandt <cb@256bit.org>2024-07-26 18:39:52 +0200
commitbe82825687fcf020dc79667cc1cdf62ace2215f2 (patch)
treebfc317b3c5984e6e901343eb3121e2183d19e883
parent8754efe437fcb17ad2c64192f8722e08d68e032e (diff)
patch 9.1.0620: Vim9: segfauls with null objectsv9.1.0620
Problem: Vim9: segfauls with null objects (after v9.1.0219) Solution: Check object pointer being NULL (Ernie Rael) fixes: #15338 closes: #15349 Signed-off-by: Ernie Rael <errael@raelity.com> Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/testdir/test_vim9_class.vim66
-rw-r--r--src/typval.c26
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c60
4 files changed, 130 insertions, 24 deletions
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 4654598465..b2ef0db98e 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -661,6 +661,31 @@ def Test_object_not_set()
Func()
END
v9.CheckSourceFailure(lines, 'E1363: Incomplete type', 1)
+
+ # Reference a object variable through a null class object which is stored in a
+ # variable of type "any".
+ lines =<< trim END
+ vim9script
+
+ def Z()
+ var o: any = null_object
+ o.v = 4
+ enddef
+ Z()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Do "echom" of a null object variable.
+ lines =<< trim END
+ vim9script
+
+ def X()
+ var x = null_object
+ echom x
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1324: Using an Object as a String', 2)
enddef
" Null object assignment and comparison
@@ -7203,6 +7228,47 @@ def Test_null_object_method_call()
T()
END
v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Calling an object method defined in a class that is extended. This differs
+ # from the previous by invoking ISN_METHODCALL instead of ISN_DCALL.
+ lines =<< trim END
+ vim9script
+
+ class C0
+ def F()
+ enddef
+ endclass
+
+ class C extends C0
+ endclass
+
+ def X()
+ var o: C0 = null_object
+ o.F()
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Getting a function ref an object method.
+ lines =<< trim END
+ vim9script
+
+ class C0
+ def F()
+ enddef
+ endclass
+
+ class C extends C0
+ endclass
+
+ def X()
+ var o: C0 = null_object
+ var XXX = o.F
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
enddef
" Test for using a dict as an object member
diff --git a/src/typval.c b/src/typval.c
index 67c819f0a4..e50e96af0f 100644
--- a/src/typval.c
+++ b/src/typval.c
@@ -267,11 +267,16 @@ tv_get_bool_or_number_chk(
break;
case VAR_OBJECT:
{
- class_T *cl = varp->vval.v_object->obj_class;
- if (cl != NULL && IS_ENUM(cl))
- semsg(_(e_using_enum_str_as_number), cl->class_name);
+ if (varp->vval.v_object == NULL)
+ emsg(_(e_using_object_as_string));
else
- emsg(_(e_using_object_as_number));
+ {
+ class_T *cl = varp->vval.v_object->obj_class;
+ if (cl != NULL && IS_ENUM(cl))
+ semsg(_(e_using_enum_str_as_number), cl->class_name);
+ else
+ emsg(_(e_using_object_as_number));
+ }
}
break;
case VAR_VOID:
@@ -1146,11 +1151,16 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
break;
case VAR_OBJECT:
{
- class_T *cl = varp->vval.v_object->obj_class;
- if (cl != NULL && IS_ENUM(cl))
- semsg(_(e_using_enum_str_as_string), cl->class_name);
- else
+ if (varp->vval.v_object == NULL)
emsg(_(e_using_object_as_string));
+ else
+ {
+ class_T *cl = varp->vval.v_object->obj_class;
+ if (cl != NULL && IS_ENUM(cl))
+ semsg(_(e_using_enum_str_as_string), cl->class_name);
+ else
+ emsg(_(e_using_object_as_string));
+ }
}
break;
case VAR_JOB:
diff --git a/src/version.c b/src/version.c
index 298d577148..806e3c542d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 620,
+/**/
619,
/**/
618,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 3a3960a8d1..40b549934b 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2254,26 +2254,35 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
{
// 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;
-
- int m_idx;
- ocmember_T *m = object_member_lookup(cl, member, 0, &m_idx);
- if (m != NULL)
+ if (obj == NULL)
{
- if (*member == '_')
- {
- emsg_var_cl_define(e_cannot_access_protected_variable_str,
- m->ocm_name, 0, cl);
- status = FAIL;
- }
-
- lidx = m_idx;
+ emsg(_(e_using_null_object));
+ status = FAIL;
}
else
{
- member_not_found_msg(cl, VAR_OBJECT, member, 0);
- status = FAIL;
+ class_T *cl = obj->obj_class;
+ char_u *member = tv_idx->vval.v_string;
+
+ int m_idx;
+ ocmember_T *m = object_member_lookup(cl, member, 0, &m_idx);
+ if (m != NULL)
+ {
+ if (*member == '_')
+ {
+ emsg_var_cl_define(
+ e_cannot_access_protected_variable_str,
+ m->ocm_name, 0, cl);
+ status = FAIL;
+ }
+
+ lidx = m_idx;
+ }
+ else
+ {
+ member_not_found_msg(cl, VAR_OBJECT, member, 0);
+ status = FAIL;
+ }
}
}
else if ((dest_type == VAR_LIST || dest_type == VAR_OBJECT)
@@ -3567,7 +3576,10 @@ exec_instructions(ectx_T *ectx)
p = tv_get_string_buf(tv, buf);
}
else
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
p = tv_stringify(tv, buf);
+ }
len = (int)STRLEN(p);
if (GA_GROW_FAILS(&ga, len + 2))
@@ -4380,7 +4392,14 @@ exec_instructions(ectx_T *ectx)
object_required_error(tv);
goto on_error;
}
+
object_T *obj = tv->vval.v_object;
+ if (obj == NULL)
+ {
+ emsg(_(e_using_null_object));
+ goto on_error;
+ }
+
class_T *cl = obj->obj_class;
// convert the interface index to the object index
@@ -4536,12 +4555,21 @@ exec_instructions(ectx_T *ectx)
tv = STACK_TV_BOT(-1);
if (tv->v_type != VAR_OBJECT)
{
+ SOURCING_LNUM = iptr->isn_lnum;
object_required_error(tv);
vim_free(pt);
goto on_error;
}
object_T *obj = tv->vval.v_object;
+ if (obj == NULL)
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ emsg(_(e_using_null_object));
+ vim_free(pt);
+ goto on_error;
+ }
+
cl = obj->obj_class;
// drop the value from the stack
clear_tv(tv);