1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2002-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include <cstring>
31 
32 #include <ostream>
33 #include <sstream>
34 #include <new>
35 
36 #include "quit.h"
37 
38 sig_atomic_t octave_interrupt_state = 0;
39 
40 // DEPRECATED in Octave 6.
41 // This variable should never have been public.
42 sig_atomic_t octave_exception_state = 0;
43 // Use this variable internally until the functions that use it can be
44 // removed.
45 static sig_atomic_t internal_exception_state;
46 
47 volatile sig_atomic_t octave_signal_caught = 0;
48 
49 void (*octave_signal_hook) (void) = nullptr;
50 void (*octave_interrupt_hook) (void) = nullptr;
51 
52 // DEPRECATED in Octave 6.
53 void (*octave_bad_alloc_hook) (void) = nullptr;
54 
55 // The octave_exception enum values were DEPRECATED in Octave 6.
56 // Use these values internally until the functions that use them can be
57 // removed.
58 enum octave_internal_exception
59 {
60   octave_internal_no_exception = 0,
61   octave_internal_exec_exception = 1,
62   octave_internal_alloc_exception = 3,
63   octave_internal_quit_exception = 4
64 };
65 
66 namespace octave
67 {
stack_trace(void) const68   std::string execution_exception::stack_trace (void) const
69   {
70     std::size_t nframes = m_stack_info.size ();
71 
72     if (nframes == 0)
73       return std::string ();
74 
75     std::ostringstream buf;
76 
77     buf << "error: called from\n";
78 
79     for (const auto& frm : m_stack_info)
80       {
81         buf << "    " << frm.fcn_name ();
82 
83         int line = frm.line ();
84 
85         if (line > 0)
86           {
87             buf << " at line " << line;
88 
89             int column = frm.column ();
90 
91             if (column > 0)
92               buf << " column " << column;
93           }
94 
95         buf << "\n";
96       }
97 
98     return buf.str ();
99   }
100 
display(std::ostream & os) const101   void execution_exception::display (std::ostream& os) const
102   {
103     if (! m_message.empty ())
104       {
105         os << m_err_type << ": " << m_message;
106 
107         if (m_message.back () != '\n')
108           {
109             os << "\n";
110 
111             std::string st = stack_trace ();
112 
113             if (! st.empty ())
114               os << st;
115           }
116       }
117   }
118 }
119 
120 void
octave_handle_signal(void)121 octave_handle_signal (void)
122 {
123   if (octave_signal_hook)
124     octave_signal_hook ();
125 
126   if (octave_interrupt_state > 0)
127     {
128       octave_interrupt_state = -1;
129 
130       throw octave::interrupt_exception ();
131     }
132 }
133 
134 // DEPRECATED in Octave 6
135 void
octave_throw_interrupt_exception(void)136 octave_throw_interrupt_exception (void)
137 {
138   if (octave_interrupt_hook)
139     octave_interrupt_hook ();
140 
141   throw octave::interrupt_exception ();
142 }
143 
144 // DEPRECATED in Octave 6
145 void
octave_throw_execution_exception(void)146 octave_throw_execution_exception (void)
147 {
148   // FIXME: would a hook function be useful here?
149 
150   internal_exception_state = octave_internal_exec_exception;
151 
152   throw octave::execution_exception ();
153 }
154 
155 // DEPRECATED in Octave 6
156 void
octave_throw_bad_alloc(void)157 octave_throw_bad_alloc (void)
158 {
159   internal_exception_state = octave_internal_alloc_exception;
160 
161   throw std::bad_alloc ();
162 }
163 
164 // DEPRECATED in Octave 6
165 void
octave_rethrow_exception(void)166 octave_rethrow_exception (void)
167 {
168   if (octave_interrupt_state)
169     {
170       octave_interrupt_state = -1;
171 
172       throw octave::interrupt_exception ();
173     }
174   else
175     {
176       switch (internal_exception_state)
177         {
178         case octave_internal_exec_exception:
179           throw octave::execution_exception ();
180           break;
181 
182         case octave_internal_alloc_exception:
183           throw std::bad_alloc ();
184           break;
185 
186         default:
187           break;
188         }
189     }
190 }
191