mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.1609: crash when an object indirectly references itself
Problem: Crash when an object indirectly references itself. Solution: Avoid clearing an object while it is already being cleared. (closes #12494)
This commit is contained in:
@@ -925,6 +925,33 @@ func Test_class_garbagecollect()
|
|||||||
echo Point.pl Point.pd
|
echo Point.pl Point.pd
|
||||||
END
|
END
|
||||||
call v9.CheckScriptSuccess(lines)
|
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
|
endfunc
|
||||||
|
|
||||||
def Test_class_function()
|
def Test_class_function()
|
||||||
|
@@ -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 */
|
||||||
|
/**/
|
||||||
|
1609,
|
||||||
/**/
|
/**/
|
||||||
1608,
|
1608,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -1497,6 +1497,9 @@ copy_object(typval_T *from, typval_T *to)
|
|||||||
static void
|
static void
|
||||||
object_clear(object_T *obj)
|
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;
|
class_T *cl = obj->obj_class;
|
||||||
|
|
||||||
// the member values are just after the object structure
|
// the member values are just after the object structure
|
||||||
@@ -1619,6 +1622,8 @@ object_created(object_T *obj)
|
|||||||
first_object = obj;
|
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.
|
* 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".
|
* It is removed from the list headed by "first_object".
|
||||||
@@ -1632,6 +1637,10 @@ object_cleared(object_T *obj)
|
|||||||
obj->obj_prev_used->obj_next_used = obj->obj_next_used;
|
obj->obj_prev_used->obj_next_used = obj->obj_next_used;
|
||||||
else if (first_object == obj)
|
else if (first_object == obj)
|
||||||
first_object = obj->obj_next_used;
|
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,11 +1650,10 @@ object_cleared(object_T *obj)
|
|||||||
object_free_nonref(int copyID)
|
object_free_nonref(int copyID)
|
||||||
{
|
{
|
||||||
int did_free = FALSE;
|
int did_free = FALSE;
|
||||||
object_T *next_obj;
|
|
||||||
|
|
||||||
for (object_T *obj = first_object; obj != NULL; obj = next_obj)
|
for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj)
|
||||||
{
|
{
|
||||||
next_obj = obj->obj_next_used;
|
next_nonref_obj = obj->obj_next_used;
|
||||||
if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
|
if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
|
||||||
{
|
{
|
||||||
// Free the object and items it contains.
|
// Free the object and items it contains.
|
||||||
@@ -1654,6 +1662,7 @@ object_free_nonref(int copyID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_nonref_obj = NULL;
|
||||||
return did_free;
|
return did_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user