Mercurial > vim
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; }