diff src/vim9class.c @ 32555:5c4c2d82d751 v9.0.1609

patch 9.0.1609: crash when an object indirectly references itself Commit: https://github.com/vim/vim/commit/f7ca56f7193f8b383be43f1f6b3a6c6ca77b4233 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 5 16:53:25 2023 +0100 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)
author Bram Moolenaar <Bram@vim.org>
date Mon, 05 Jun 2023 18:00:04 +0200
parents feb9a581eb00
children 448aef880252
line wrap: on
line diff
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -1497,6 +1497,9 @@ copy_object(typval_T *from, typval_T *to
     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,6 +1622,8 @@ object_created(object_T *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.
  * 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;
     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,11 +1650,10 @@ object_cleared(object_T *obj)
 object_free_nonref(int copyID)
 {
     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))
 	{
 	    // Free the object and items it contains.
@@ -1654,6 +1662,7 @@ object_free_nonref(int copyID)
 	}
     }
 
+    next_nonref_obj = NULL;
     return did_free;
 }