changeset 27280:8d30dc86e5d9

Fix freeing graphics objects (bug #55908). * grahphics.cc (do_delete_children): Use while loop when not deleting from root because "children_list" shrinks. (do_free): Special case for deleting a figure. (delete_graphics_object): Remove figures from root.
author Markus Mützel <markus.muetzel@gmx.de>
date Mon, 22 Jul 2019 20:05:55 +0200
parents 1c8b20731af4
children 0915fec3d3a9
files libinterp/corefcn/graphics.cc
diffstat 1 files changed, 37 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.cc	Sat Mar 09 22:09:25 2019 +0100
+++ b/libinterp/corefcn/graphics.cc	Mon Jul 22 20:05:55 2019 +0200
@@ -1806,15 +1806,29 @@
 void
 children_property::do_delete_children (bool clear, bool from_root)
 {
-  for (graphics_handle hchild : children_list)
-    {
-      graphics_object go = gh_manager::get_object (hchild);
-
-      if (hchild.value () > 0 && go.valid_object ()
-          && ! go.get_properties ().is_beingdeleted ())
-        gh_manager::free (hchild, from_root);
-    }
-
+  if (from_root)
+    {
+      for (graphics_handle hchild : children_list)
+        {
+          graphics_object go = gh_manager::get_object (hchild);
+          if (go.valid_object ()
+              && ! go.get_properties ().is_beingdeleted ())
+            gh_manager::free (hchild, from_root);
+        }
+      children_list.clear ();
+    }
+  else
+    while (! children_list.empty ())
+      {
+        // gh_manager::free removes hchild from children_list
+        graphics_handle hchild = children_list.front ();
+        graphics_object go = gh_manager::get_object (hchild);
+        if (go.valid_object ()
+            && ! go.get_properties ().is_beingdeleted ())
+          gh_manager::free (hchild, from_root);
+      }
+
+  // FIXME: children_list should be clear anyway at this point.
   if (clear)
     children_list.clear ();
 }
@@ -2756,6 +2770,14 @@
   return retval;
 }
 
+static bool
+isfigure (double val)
+{
+  graphics_object go = gh_manager::get_object (val);
+
+  return go && go.isa ("figure");
+}
+
 void
 gh_manager::do_free (const graphics_handle& h, bool from_root)
 {
@@ -2776,7 +2798,7 @@
 
       graphics_handle parent_h = p->second.get_parent ();
       graphics_object parent_go = nullptr;
-      if (! from_root)
+      if (! from_root || isfigure (h.value ()))
         parent_go = gh_manager::get_object (parent_h);
 
       bp.set_beingdeleted (true);
@@ -2784,7 +2806,7 @@
       // delete listeners before invalidating object
       p->second.remove_all_listeners ();
 
-      bp.delete_children ();
+      bp.delete_children (true, from_root);
 
       // NOTE: Call the delete function while the object's state is still valid.
       octave_value val = bp.get_deletefcn ();
@@ -2798,7 +2820,8 @@
       // NOTE: Call remove_child before erasing the go from the map if not
       // removing from groot.
       // A callback function might have already deleted the parent
-      if (! from_root && parent_go.valid_object () && h.ok ())
+      if ((! from_root || isfigure (h.value ())) && parent_go.valid_object ()
+          && h.ok ())
         parent_go.remove_child (h);
 
       // Note: this will be valid only for first explicitly deleted
@@ -2937,7 +2960,7 @@
           // NOTE: Freeing the handle also calls any deletefcn.  It also calls
           //       the parent's delete_child function.
 
-          gh_manager::free (h, from_root);
+          gh_manager::free (h, from_root || go.isa ("figure"));
 
           Vdrawnow_requested = true;
         }
@@ -2947,7 +2970,7 @@
 static void
 delete_graphics_object (double val, bool from_root = false)
 {
-  delete_graphics_object (gh_manager::lookup (val), from_root);
+  delete_graphics_object (gh_manager::lookup (val), from_root || isfigure (val));
 }
 
 // Flag to stop redraws due to callbacks while deletion is in progress.
@@ -3072,14 +3095,6 @@
   return retval;
 }
 
-static bool
-isfigure (double val)
-{
-  graphics_object go = gh_manager::get_object (val);
-
-  return go && go.isa ("figure");
-}
-
 static void
 xcreatefcn (const graphics_handle& h)
 {