diff libgui/src/interpreter-qobject.cc @ 27695:cdb681adc85a

improve exit behavior with qt graphics toolkit (bug #56952) When I was able to reproduce it, the crash described in bug report #56952 appeared to be happening when the Qt event loop was calling QtHandles::qt_graphics_toolkit::create_object when the interpreter was being deleted and the gh_manager object was already invalid, so attempting to lock the mutex it contains lead to a segfault. This change attempts to avoid that possibility by disabling the Qt graphics toolkit when interpreter_qobject::execute is finished with the interpreter. We also allow the the qt_application object to delete the interpreter. * interpreter-qobject.h, interpreter-qobject.cc (interpreter_qobject::graphics_fini): New function. (interpreter_qobject::execute): Use an unwind_action to ensure that graphics_fini is called after the interpreter is finished executing commands. Don't explicitly delete the interpreter. Allow the application context to do that job.
author John W. Eaton <jwe@octave.org>
date Fri, 15 Nov 2019 10:37:33 -0500
parents b3401292e101
children 5e8891dceec7
line wrap: on
line diff
--- a/libgui/src/interpreter-qobject.cc	Thu Nov 14 21:35:14 2019 -0500
+++ b/libgui/src/interpreter-qobject.cc	Fri Nov 15 10:37:33 2019 -0500
@@ -36,6 +36,8 @@
 #include "qt-graphics-toolkit.h"
 #include "qt-interpreter-events.h"
 
+#include "unwind-prot.h"
+
 #include "graphics.h"
 #include "gtk-manager.h"
 #include "input.h"
@@ -54,6 +56,9 @@
 
     qt_application& app_context = m_octave_qobj.app_context ();
 
+    // The application context will own the interpreter.  It is
+    // responsible for cleaning it up when the application exits.
+
     interpreter& interp = app_context.create_interpreter ();
 
     event_manager& evmgr = interp.get_event_manager ();
@@ -79,8 +84,8 @@
 
         if (interp.initialized ())
           {
-            // The interpreter should be completely ready at this point so let
-            // the GUI know.
+            // The interpreter should be completely ready at this point
+            // so let the GUI know.
 
             m_interpreter = &interp;
 
@@ -88,6 +93,14 @@
 
             graphics_init ();
 
+            // We created the Qt graphics toolkit and interperter here.
+            // Disable and delete it when the interpreter is done
+            // executing commands for us.  Use an unwind_action to
+            // ensure that it is disabled and deleted even if we exit
+            // this code block becuase an exception is thrown.
+
+            unwind_action ([this] (void) { graphics_fini (); });
+
             // Start executing commands in the command window.
 
             exit_status = interp.execute ();
@@ -102,11 +115,6 @@
 
     m_interpreter = nullptr;
 
-    // Whether or not initialization succeeds we need to clean up the
-    // interpreter once we are done with it.
-
-    app_context.delete_interpreter ();
-
     emit octave_finished_signal (exit_status);
   }
 
@@ -119,6 +127,9 @@
   {
 #if defined (HAVE_QT_GRAPHICS)
 
+    if (! m_interpreter)
+      return;
+
     gh_manager& gh_mgr = m_interpreter->get_gh_manager ();
 
     autolock guard (gh_mgr.graphics_lock ());
@@ -145,6 +156,26 @@
 #endif
   }
 
+  void interpreter_qobject::graphics_fini (void)
+  {
+#if defined (HAVE_QT_GRAPHICS)
+
+    if (! m_interpreter)
+      return;
+
+    octave::gtk_manager& gtk_mgr = m_interpreter->get_gtk_manager ();
+
+    gtk_mgr.unregister_toolkit ("qt");
+
+    gtk_mgr.unload_toolkit ("qt");
+
+    delete m_graphics_toolkit;
+
+    m_graphics_toolkit = nullptr;
+
+#endif
+  }
+
   void interpreter_qobject::interpreter_event (const fcn_callback& fcn)
   {
     if (! m_interpreter)