changeset 22504:2aa9e8893ea9

Fix crash in evalc (bug #49057). * oct-parse.in.yy (maybe_print_last_error_message, restore_octave_stdout, restore_octave_stderr): New functions. * oct-parse.in.yy (Fevalc): Replace try/catch block with unwind_protect. Register three new functions above to be called if an error is encountered.
author Mike Miller <mtmiller@octave.org>
date Fri, 16 Sep 2016 09:22:33 -0700
parents 05c2313904cb
children 7bdc80232cdc
files libinterp/parse-tree/oct-parse.in.yy
diffstat 1 files changed, 33 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/oct-parse.in.yy	Fri Sep 16 11:53:12 2016 +0900
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri Sep 16 09:22:33 2016 -0700
@@ -5319,6 +5319,30 @@
   return retval;
 }
 
+static void
+maybe_print_last_error_message (bool *doit)
+{
+  if (doit && *doit)
+    // Print error message again, which was lost because of the stderr buffer
+    // Note: this keeps error_state and last_error_stack intact
+    message_with_id ("error", last_error_id ().c_str (),
+                     last_error_message ().c_str ());
+}
+
+static void
+restore_octave_stdout (std::streambuf *buf)
+{
+  octave_stdout.flush ();
+  octave_stdout.rdbuf (buf);
+}
+
+static void
+restore_octave_stderr (std::streambuf *buf)
+{
+  std::cerr.flush ();
+  std::cerr.rdbuf (buf);
+}
+
 DEFUN (evalc, args, nargout,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{s} =} evalc (@var{try})
@@ -5365,38 +5389,20 @@
   std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ());
   std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ());
 
+  bool eval_error_occurred = true;
+
+  octave::unwind_protect frame;
+
+  frame.add_fcn (maybe_print_last_error_message, &eval_error_occurred);
+  frame.add_fcn (restore_octave_stdout, old_out_buf);
+  frame.add_fcn (restore_octave_stderr, old_err_buf);
 
   // call standard eval function
   octave_value_list retval;
   int eval_nargout = std::max (0, nargout - 1);
 
-  const octave::execution_exception* eval_exception = 0;
-  try
-    {
-      retval = Feval (args, eval_nargout);
-    }
-  catch (const octave::execution_exception& e)
-    {
-      // hold back exception from eval until we have restored streams
-      eval_exception = &e;
-    }
-
-  // stop capturing buffer and restore stdout/stderr
-  out_stream.flush ();
-  err_stream.flush ();
-
-  out_stream.rdbuf (old_out_buf);
-  err_stream.rdbuf (old_err_buf);
-
-  if (eval_exception)
-    {
-      // Print error message again, which was lost because of the stderr buffer
-      // Note: this keeps error_state and last_error_stack intact
-      message_with_id ("error", last_error_id ().c_str (),
-                       last_error_message ().c_str ());
-      // rethrow original exception from above
-      throw *eval_exception;
-    }
+  retval = Feval (args, eval_nargout);
+  eval_error_occurred = false;
 
   retval.prepend (buffer.str ());
   return retval;