# HG changeset patch # User Christian Brabandt # Date 1693859403 -7200 # Node ID 13258b342d3823fc2f11e3fc9e9f915c0228aae0 # Parent 13914615534e6f9e5a67af02056a840b9ef94fbb patch 9.0.1865: Vim9: garbage collection may cause crash Commit: https://github.com/vim/vim/commit/544be0d893e68c494aed09232d5bee4ca8b74619 Author: Yegappan Lakshmanan Date: Mon Sep 4 22:14:28 2023 +0200 patch 9.0.1865: Vim9: garbage collection may cause crash Problem: Vim9: garbage collection may cause crash Solution: validate that class members typeval is not null closes: #13028 Signed-off-by: Christian Brabandt Co-authored-by: Yegappan Lakshmanan diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -5725,10 +5725,15 @@ set_ref_in_item_class( return FALSE; cl->class_copyID = copyID; - for (int i = 0; !abort && i < cl->class_class_member_count; ++i) - abort = abort || set_ref_in_item( - &cl->class_members_tv[i], - copyID, ht_stack, list_stack); + if (cl->class_members_tv != NULL) + { + // The "class_members_tv" table is allocated only for regular classes + // and not for interfaces. + for (int i = 0; !abort && i < cl->class_class_member_count; ++i) + abort = abort || set_ref_in_item( + &cl->class_members_tv[i], + copyID, ht_stack, list_stack); + } for (int i = 0; !abort && i < cl->class_class_function_count; ++i) abort = abort || set_ref_in_func(NULL, diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -1307,6 +1307,60 @@ func Test_class_garbagecollect() call v9.CheckScriptSuccess(lines) endfunc +" Test interface garbage collection +func Test_interface_garbagecollect() + let lines =<< trim END + vim9script + + interface I + static ro_class_var: number + public static rw_class_var: number + static _priv_class_var: number + this.ro_obj_var: number + public this.rw_obj_var: number + this._priv_obj_var: number + + static def ClassFoo(): number + static def _ClassBar(): number + def ObjFoo(): number + def _ObjBar(): number + endinterface + + class A implements I + static ro_class_var: number = 10 + public static rw_class_var: number = 20 + static _priv_class_var: number = 30 + this.ro_obj_var: number = 40 + public this.rw_obj_var: number = 50 + this._priv_obj_var: number = 60 + + static def _ClassBar(): number + return _priv_class_var + enddef + + static def ClassFoo(): number + return ro_class_var + rw_class_var + A._ClassBar() + enddef + + def _ObjBar(): number + return this._priv_obj_var + enddef + + def ObjFoo(): number + return this.ro_obj_var + this.rw_obj_var + this._ObjBar() + enddef + endclass + + assert_equal(60, A.ClassFoo()) + var o = A.new() + assert_equal(150, o.ObjFoo()) + test_garbagecollect_now() + assert_equal(60, A.ClassFoo()) + assert_equal(150, o.ObjFoo()) + END + call v9.CheckScriptSuccess(lines) +endfunc + def Test_class_function() var lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1865, +/**/ 1864, /**/ 1863,