diff options
author | Ernie Rael <errael@raelity.com> | 2024-07-26 18:37:02 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2024-07-26 18:39:52 +0200 |
commit | be82825687fcf020dc79667cc1cdf62ace2215f2 (patch) | |
tree | bfc317b3c5984e6e901343eb3121e2183d19e883 | |
parent | 8754efe437fcb17ad2c64192f8722e08d68e032e (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.vim | 66 | ||||
-rw-r--r-- | src/typval.c | 26 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9execute.c | 60 |
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); |