Mercurial > octave
changeset 20666:e0e2c2ce7e94
defer stack trace until back at top level
* error.cc (debug_or_throw_exception): New arg, show_stack_trace.
Store stack trace info in exception object. Change all uses.
(pr_where, pr_where_1, pr_where_2): New arg, os. Write to it instead
of writing to std::cerr unconditionally. Change all uses.
(error_1): Don't print stack trace here, just determine whether stack
trace should be shown by the current exception.
* toplev.cc (main_loop): Display stack trace when catching
octave_execution_exception.
* ov-base.cc (octave_base_value::cell_value,
octave_base_value::string_value): Use gripe_wrong_type_arg.
* oct-parse.in.yy (Feval, Fevalin): Also call recover_from_exception
when handling octave_execution_exception.
* pt-eval.cc (tree_evaluator::visit_try_catch_command,
tree_evaluator::do_unwind_protect_cleanup): Also call recover_from_exception
when handling octave_execution_exception.
* quit.h (octave_execution_exception): Extend class to handle a text
message for stack trace info.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 23 Oct 2015 16:55:23 -0400 |
parents | 67e6343cd29a |
children | 8742e0b1cc49 |
files | libinterp/corefcn/error.cc libinterp/corefcn/toplev.cc libinterp/octave-value/ov-base.cc libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-eval.cc liboctave/cruft/misc/quit.h |
diffstat | 6 files changed, 151 insertions(+), 83 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/error.cc Wed Oct 28 22:34:43 2015 +0000 +++ b/libinterp/corefcn/error.cc Fri Oct 23 16:55:23 2015 -0400 @@ -134,63 +134,6 @@ } static void -debug_or_throw_exception (void) -{ - if ((interactive || forced_interactive) - && Vdebug_on_error && octave_call_stack::caller_user_code ()) - { - unwind_protect frame; - frame.protect_var (Vdebug_on_error); - Vdebug_on_error = false; - - tree_evaluator::debug_mode = true; - - tree_evaluator::current_frame = octave_call_stack::current_frame (); - - do_keyboard (octave_value_list ()); - } - else - octave_throw_execution_exception (); -} - -// Warning messages are never buffered. - -static void -vwarning (const char *name, const char *id, const char *fmt, va_list args) -{ - if (discard_warning_messages) - return; - - flush_octave_stdout (); - - std::ostringstream output_buf; - - octave_vformat (output_buf, fmt, args); - - // FIXME: we really want to capture the message before it has all the - // formatting goop attached to it. We probably also want just the - // message, not the traceback information. - - std::string base_msg = output_buf.str (); - std::string msg_string; - - if (name) - msg_string = std::string (name) + ": "; - - msg_string += base_msg + "\n"; - - Vlast_warning_id = id; - Vlast_warning_message = base_msg; - - if (! Vquiet_warning) - { - octave_diary << msg_string; - - std::cerr << msg_string; - } -} - -static void verror (bool save_last_error, std::ostream& os, const char *name, const char *id, const char *fmt, va_list args, bool with_cfn = false) @@ -272,7 +215,7 @@ } static void -pr_where_2 (const char *fmt, va_list args) +pr_where_2 (std::ostream& os, const char *fmt, va_list args) { if (fmt) { @@ -288,12 +231,12 @@ { char *tmp_fmt = strsave (fmt); tmp_fmt[len - 1] = '\0'; - verror (false, std::cerr, 0, "", tmp_fmt, args); + verror (false, os, 0, "", tmp_fmt, args); delete [] tmp_fmt; } } else - verror (false, std::cerr, 0, "", fmt, args); + verror (false, os, 0, "", fmt, args); } } } @@ -302,16 +245,16 @@ } static void -pr_where_1 (const char *fmt, ...) +pr_where_1 (std::ostream& os, const char *fmt, ...) { va_list args; va_start (args, fmt); - pr_where_2 (fmt, args); + pr_where_2 (os, fmt, args); va_end (args); } static void -pr_where (const char *who) +pr_where (std::ostream& os, const char *who) { std::list<octave_call_stack::stack_frame> frames = octave_call_stack::backtrace_frames (); @@ -319,7 +262,7 @@ size_t nframes = frames.size (); if (nframes > 0) - pr_where_1 ("%s: called from\n", who); + pr_where_1 (os, "%s: called from\n", who); // Print the error message only if it is different from the previous one; // Makes the output more concise and readable. @@ -334,11 +277,85 @@ int line = elt.line (); int column = elt.column (); - pr_where_1 (" %s at line %d column %d\n", + pr_where_1 (os, " %s at line %d column %d\n", fcn_name.c_str (), line, column); } } +static void +debug_or_throw_exception (bool show_stack_trace = false) +{ + if ((interactive || forced_interactive) + && Vdebug_on_error && octave_call_stack::caller_user_code ()) + { + unwind_protect frame; + frame.protect_var (Vdebug_on_error); + Vdebug_on_error = false; + + tree_evaluator::debug_mode = true; + + tree_evaluator::current_frame = octave_call_stack::current_frame (); + + if (show_stack_trace) + pr_where (std::cerr, "error"); + + do_keyboard (octave_value_list ()); + } + else + { + octave_execution_exception e; + + if (show_stack_trace + && octave_exception_state != octave_exec_exception) + { + std::ostringstream buf; + pr_where (buf, "error"); + e.set_stack_trace (buf.str ()); + } + + octave_exception_state = octave_exec_exception; + + throw e; + } +} + +// Warning messages are never buffered. + +static void +vwarning (const char *name, const char *id, const char *fmt, va_list args) +{ + if (discard_warning_messages) + return; + + flush_octave_stdout (); + + std::ostringstream output_buf; + + octave_vformat (output_buf, fmt, args); + + // FIXME: we really want to capture the message before it has all the + // formatting goop attached to it. We probably also want just the + // message, not the traceback information. + + std::string base_msg = output_buf.str (); + std::string msg_string; + + if (name) + msg_string = std::string (name) + ": "; + + msg_string += base_msg + "\n"; + + Vlast_warning_id = id; + Vlast_warning_message = base_msg; + + if (! Vquiet_warning) + { + octave_diary << msg_string; + + std::cerr << msg_string; + } +} + void vmessage (const char *name, const char *fmt, va_list args) { @@ -412,6 +429,8 @@ error_1 (std::ostream& os, const char *name, const char *id, const char *fmt, va_list args, bool with_cfn = false) { + bool show_stack_trace = false; + if (fmt) { if (*fmt) @@ -437,7 +456,7 @@ bool in_user_code = octave_call_stack::caller_user_code () != 0; if (in_user_code && ! discard_error_messages) - pr_where ("error"); + show_stack_trace = true; } } } @@ -445,7 +464,7 @@ else panic ("error_1: invalid format"); - debug_or_throw_exception (); + debug_or_throw_exception (show_stack_trace); } void @@ -632,7 +651,7 @@ if (! fmt_suppresses_backtrace && in_user_code && Vbacktrace_on_warning && ! discard_warning_messages) - pr_where ("warning"); + pr_where (std::cerr, "warning"); if ((interactive || forced_interactive) && Vdebug_on_warning && in_user_code) @@ -896,10 +915,11 @@ if (l > 0) { if (c > 0) - pr_where_1 ("error: near line %d, column %d", + pr_where_1 (std::cerr, + "error: near line %d, column %d", l, c); else - pr_where_1 ("error: near line %d", l); + pr_where_1 (std::cerr, "error: near line %d", l); } } else @@ -907,10 +927,12 @@ if (l > 0) { if (c > 0) - pr_where_1 ("error: called from '%s' near line %d, column %d", + pr_where_1 (std::cerr, + "error: called from '%s' near line %d, column %d", nm.c_str (), l, c); else - pr_where_1 ("error: called from '%d' near line %d", + pr_where_1 (std::cerr, + "error: called from '%d' near line %d", nm.c_str (), l); } } @@ -922,10 +944,12 @@ if (l > 0) { if (c > 0) - pr_where_1 ("error: in file %s near line %d, column %d", + pr_where_1 (std::cerr, + "error: in file %s near line %d, column %d", file.c_str (), l, c); else - pr_where_1 ("error: in file %s near line %d", + pr_where_1 (std::cerr, + "error: in file %s near line %d", file.c_str (), l); } } @@ -934,10 +958,12 @@ if (l > 0) { if (c > 0) - pr_where_1 ("error: called from '%s' in file %s near line %d, column %d", + pr_where_1 (std::cerr, + "error: called from '%s' in file %s near line %d, column %d", nm.c_str (), file.c_str (), l, c); else - pr_where_1 ("error: called from '%d' in file %s near line %d", + pr_where_1 (std::cerr, + "error: called from '%d' in file %s near line %d", nm.c_str (), file.c_str (), l); } }
--- a/libinterp/corefcn/toplev.cc Wed Oct 28 22:34:43 2015 +0000 +++ b/libinterp/corefcn/toplev.cc Fri Oct 23 16:55:23 2015 -0400 @@ -665,8 +665,13 @@ << e.message () << " -- trying to return to prompt" << std::endl; } - catch (const octave_execution_exception&) + catch (const octave_execution_exception& e) { + std::string stack_trace = e.info (); + + if (! stack_trace.empty ()) + std::cerr << stack_trace; + recover_from_exception (); } catch (const std::bad_alloc&)
--- a/libinterp/octave-value/ov-base.cc Wed Oct 28 22:34:43 2015 +0000 +++ b/libinterp/octave-value/ov-base.cc Fri Oct 23 16:55:23 2015 -0400 @@ -549,9 +549,7 @@ try { - std::string tn = type_name (); - - error ("wrong type argument '%s'\n", tn.c_str ()); + gripe_wrong_type_arg ("cell value", type_name ()); } catch (const octave_execution_exception&) { @@ -949,9 +947,7 @@ try { - std::string tn = type_name (); - - error ("wrong type argument '%s'\n", tn.c_str ()); + gripe_wrong_type_arg ("string value", type_name ()); } catch (const octave_execution_exception&) {
--- a/libinterp/parse-tree/oct-parse.in.yy Wed Oct 28 22:34:43 2015 +0000 +++ b/libinterp/parse-tree/oct-parse.in.yy Fri Oct 23 16:55:23 2015 -0400 @@ -4965,6 +4965,8 @@ } catch (const octave_execution_exception&) { + recover_from_exception (); + execution_error = true; } @@ -5122,6 +5124,8 @@ } catch (const octave_execution_exception&) { + recover_from_exception (); + execution_error = true; }
--- a/libinterp/parse-tree/pt-eval.cc Wed Oct 28 22:34:43 2015 +0000 +++ b/libinterp/parse-tree/pt-eval.cc Fri Oct 23 16:55:23 2015 -0400 @@ -42,6 +42,7 @@ #include "pt-all.h" #include "pt-eval.h" #include "symtab.h" +#include "toplev.h" #include "unwind-prot.h" //FIXME: This should be part of tree_evaluator @@ -867,6 +868,8 @@ } catch (const octave_execution_exception&) { + recover_from_exception (); + execution_error = true; } } @@ -937,6 +940,8 @@ } catch (const octave_execution_exception&) { + recover_from_exception (); + execution_error_in_cleanup = true; } @@ -1011,6 +1016,8 @@ } catch (const octave_execution_exception&) { + recover_from_exception (); + unwind_protect_exception = true; // Run the cleanup code on exceptions, so that it is run even in case
--- a/liboctave/cruft/misc/quit.h Wed Oct 28 22:34:43 2015 +0000 +++ b/liboctave/cruft/misc/quit.h Fri Oct 23 16:55:23 2015 -0400 @@ -30,6 +30,7 @@ #ifdef __cplusplus #include <new> +#include <string> extern "C" { #endif @@ -75,6 +76,35 @@ class octave_execution_exception { +public: + + octave_execution_exception (void) : m_stack_trace () { } + + octave_execution_exception (const octave_execution_exception& x) + : m_stack_trace (x.m_stack_trace) { } + + octave_execution_exception& operator = (const octave_execution_exception& x) + { + if (&x != this) + m_stack_trace = x.m_stack_trace; + + return *this; + } + + ~octave_execution_exception (void) { } + + virtual void set_stack_trace (const std::string& st) + { + m_stack_trace = st; + } + + virtual std::string info (void) const + { + return m_stack_trace; + } + +private: + std::string m_stack_trace; }; class