To: vim_dev@googlegroups.com Subject: Patch 9.0.1609 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1609 Problem: Crash when an object indirectly references itself. Solution: Avoid clearing an object while it is already being cleared. (closes #12494) Files: src/vim9class.c, src/testdir/test_vim9_class.vim *** ../vim-9.0.1608/src/vim9class.c 2023-06-04 18:11:31.998816728 +0100 --- src/vim9class.c 2023-06-05 16:39:27.490940490 +0100 *************** *** 1497,1502 **** --- 1497,1505 ---- static void object_clear(object_T *obj) { + // Avoid a recursive call, it can happen if "obj" has a circular reference. + obj->obj_refcount = INT_MAX; + class_T *cl = obj->obj_class; // the member values are just after the object structure *************** *** 1619,1624 **** --- 1622,1629 ---- first_object = obj; } + static object_T *next_nonref_obj = NULL; + /* * Call this function when an object has been cleared and is about to be freed. * It is removed from the list headed by "first_object". *************** *** 1632,1637 **** --- 1637,1646 ---- obj->obj_prev_used->obj_next_used = obj->obj_next_used; else if (first_object == obj) first_object = obj->obj_next_used; + + // update the next object to check if needed + if (obj == next_nonref_obj) + next_nonref_obj = obj->obj_next_used; } /* *************** *** 1641,1651 **** object_free_nonref(int copyID) { int did_free = FALSE; - object_T *next_obj; ! for (object_T *obj = first_object; obj != NULL; obj = next_obj) { ! next_obj = obj->obj_next_used; if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) { // Free the object and items it contains. --- 1650,1659 ---- object_free_nonref(int copyID) { int did_free = FALSE; ! for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj) { ! next_nonref_obj = obj->obj_next_used; if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) { // Free the object and items it contains. *************** *** 1654,1659 **** --- 1662,1668 ---- } } + next_nonref_obj = NULL; return did_free; } *** ../vim-9.0.1608/src/testdir/test_vim9_class.vim 2023-06-04 18:11:31.998816728 +0100 --- src/testdir/test_vim9_class.vim 2023-06-05 15:45:05.119622922 +0100 *************** *** 925,930 **** --- 925,957 ---- echo Point.pl Point.pd END call v9.CheckScriptSuccess(lines) + + let lines =<< trim END + vim9script + + interface View + endinterface + + class Widget + this.view: View + endclass + + class MyView implements View + this.widget: Widget + + def new() + # this will result in a circular reference to this object + this.widget = Widget.new(this) + enddef + endclass + + var view = MyView.new() + + # overwrite "view", will be garbage-collected next + view = MyView.new() + test_garbagecollect_now() + END + call v9.CheckScriptSuccess(lines) endfunc def Test_class_function() *** ../vim-9.0.1608/src/version.c 2023-06-05 15:00:00.343485274 +0100 --- src/version.c 2023-06-05 15:43:14.115773128 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1609, /**/ -- Support your right to bare arms! Wear short sleeves! /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///