monotone

monotone Mtn Source Tree

Root/main.cc

1
2// This file is derived from execution_monitor.cpp, a part of boost.
3//
4// the error reporting mechanisms in that file were irritating to our
5// users, so we've just copied and modified the code, cleaning up
6// parts of it in the process.
7//
8// it is somewhat likely that you actually want to look in monotone.cc for
9// cpp_main(), which is the function which does more interesting stuff. all
10// this file does is interface with the operating system error reporting
11// mechanisms to ensure that we back out of SEGV and friends using
12// exceptions, and translate system exceptions to something helpful for a
13// user doing debugging or error reporting.
14
15#include <boost/cstdlib.hpp>
16#include <boost/config.hpp>
17#include <string>
18#include <new>
19#include <typeinfo>
20#include <exception>
21#include <stdexcept>
22#include <cstring>
23#include <iostream>
24#include <ui.hh>
25
26// Microsoft + other compatible compilers such as Intel
27#if defined(_MSC_VER) || (defined(__MWERKS__) && __MWERKS__ >= 0x3000)
28#define MS_STRUCTURED_EXCEPTION_HANDLING
29#include <wtypes.h>
30#include <winbase.h>
31#include <excpt.h>
32#include <eh.h>
33#if !defined(__MWERKS__)
34#define MS_CRT_DEBUG_HOOK
35#include <crtdbg.h>
36#endif
37
38#elif (defined(__BORLANDC__) && defined(_Windows))
39#define MS_STRUCTURED_EXCEPTION_HANDLING
40#include <windows.h> // Borland 5.5.1 has its own way of doing things.
41
42#elif (defined(__GNUC__) && defined(__MINGW32__))
43#define MS_STRUCTURED_EXCEPTION_HANDLING
44#include <windows.h>
45
46#elif defined(__unix) || defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__)
47#define UNIX_STYLE_SIGNAL_HANDLING
48#include <unistd.h>
49#include <csignal>
50#include <csetjmp>
51
52#else
53#error "no known OS signal handling interface"
54#endif
55
56
57// A rough outline of what this file does:
58//
59// runs main()
60// - sets up a try block to catch the_one_true_exception
61// - calls main_with_many_flavours_of_exception
62// + sets up a try block with a zillion little exception handlers
63// all of which translate into the_one_true_exception
64// + installs structured exception handler and assertion handler
65// for microsoft systems
66// + calls main_with_optional_signal_handling
67// * sets up a unix sigjump_buf if appropriate
68// * calls cpp_main
69
70extern int
71cpp_main(int argc, char ** argv);
72
73static const size_t
74REPORT_ERROR_BUFFER_SIZE = 512;
75
76#ifdef BOOST_NO_STDC_NAMESPACE
77namespace std { using ::strlen; using ::strncat; }
78#endif
79
80struct
81the_one_true_exception
82{
83 static char buf[REPORT_ERROR_BUFFER_SIZE];
84 explicit the_one_true_exception(char const *msg1, char const *msg2)
85 {
86 buf[0] = '\0';
87 std::strncat(buf, msg1, sizeof(buf)-1);
88 std::strncat(buf, msg2, sizeof(buf)-1-std::strlen(buf));
89 }
90};
91char the_one_true_exception::buf[REPORT_ERROR_BUFFER_SIZE];
92
93static void
94report_error(char const *msg1, char const *msg2 = "")
95{
96 throw the_one_true_exception(msg1, msg2);
97}
98
99
100////////////////////////////////////////////////
101// windows style structured exception handling
102// (and assertions, which get their own support)
103////////////////////////////////////////////////
104
105#if defined(MS_CRT_DEBUG_HOOK)
106static int
107assert_reporting_function(int reportType, char* userMessage, int* retVal)
108{
109 switch (reportType)
110 {
111 case _CRT_ASSERT:
112 report_error(userMessage);
113 return 1;
114
115 case _CRT_ERROR:
116 report_error(userMessage);
117 return 1;
118
119 default:
120 return 0;
121 }
122}
123#endif
124
125#ifdef MS_STRUCTURED_EXCEPTION_HANDLING
126struct
127ms_se_exception
128{
129 unsigned int exception_id;
130 explicit ms_se_exception(unsigned int n)
131 : exception_id(n)
132 {}
133};
134
135static void
136ms_se_trans_func(unsigned int id, _EXCEPTION_POINTERS*)
137{
138 throw ms_se_exception(id);
139}
140
141static void
142report_ms_se_error(unsigned int id)
143{
144 switch (id)
145 {
146 case EXCEPTION_ACCESS_VIOLATION:
147 report_error("memory access violation");
148 break;
149
150 case EXCEPTION_ILLEGAL_INSTRUCTION:
151 report_error("illegal instruction");
152 break;
153
154 case EXCEPTION_PRIV_INSTRUCTION:
155 report_error("privilaged instruction");
156 break;
157
158 case EXCEPTION_IN_PAGE_ERROR:
159 report_error("memory page error");
160 break;
161
162 case EXCEPTION_STACK_OVERFLOW:
163 report_error("stack overflow");
164 break;
165
166 case EXCEPTION_DATATYPE_MISALIGNMENT:
167 report_error("data misalignment");
168 break;
169
170 case EXCEPTION_INT_DIVIDE_BY_ZERO:
171 report_error("integer divide by zero");
172 break;
173
174 case EXCEPTION_INT_OVERFLOW:
175 report_error("integer overflow");
176 break;
177
178 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
179 report_error("array bounds exceeded");
180 break;
181
182 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
183 report_error("floating point divide by zero");
184 break;
185
186 case EXCEPTION_FLT_STACK_CHECK:
187 report_error("floating point stack check");
188 break;
189
190 case EXCEPTION_FLT_DENORMAL_OPERAND:
191 case EXCEPTION_FLT_INEXACT_RESULT:
192 case EXCEPTION_FLT_INVALID_OPERATION:
193 case EXCEPTION_FLT_OVERFLOW:
194 case EXCEPTION_FLT_UNDERFLOW:
195 report_error("floating point error");
196 break;
197
198 default:
199 report_error("unrecognized exception or signal");
200 }
201}
202
203#if (defined(__BORLANDC__) && defined(_Windows))
204// this works for Borland but not other Win32 compilers (which trap too many cases)
205static int
206main_with_signal_handlers(int argc, char **argv)
207{
208 int result;
209 __try
210 {
211 result = cpp_main(argc, argv);
212 }
213 __except (1)
214 {
215 throw ms_se_exception(GetExceptionCode());
216 }
217 return result;
218}
219
220#else
221static int
222main_with_signal_handlers(int argc, char **argv)
223{
224 return cpp_main(argc, argv);
225}
226#endif
227
228
229/////////////////////////////
230// unix style signal handling
231/////////////////////////////
232
233#elif defined(UNIX_STYLE_SIGNAL_HANDLING)
234struct
235unix_signal_exception
236{
237 char const * error_message;
238 explicit unix_signal_exception(char const * em)
239 : error_message(em)
240 {}
241};
242
243static sigjmp_buf jump_buf;
244
245extern "C"
246{
247 static void
248 unix_style_signal_handler(int sig)
249 {
250 siglongjmp(jump_buf, sig);
251 }
252}
253
254static int
255main_with_signal_handlers(int argc, char **argv)
256{
257 typedef struct sigaction* sigaction_ptr;
258 static struct sigaction all_signals_action;
259 struct sigaction old_SIGFPE_action;
260 struct sigaction old_SIGTRAP_action;
261 struct sigaction old_SIGSEGV_action;
262 struct sigaction old_SIGBUS_action;
263 struct sigaction old_SIGABRT_action;
264
265 all_signals_action.sa_flags = 0;
266 all_signals_action.sa_handler = &unix_style_signal_handler;
267 sigemptyset(&all_signals_action.sa_mask);
268
269 sigaction(SIGFPE , &all_signals_action, &old_SIGFPE_action);
270 sigaction(SIGTRAP, &all_signals_action, &old_SIGTRAP_action);
271 sigaction(SIGSEGV, &all_signals_action, &old_SIGSEGV_action);
272 sigaction(SIGBUS , &all_signals_action, &old_SIGBUS_action);
273 sigaction(SIGABRT, &all_signals_action, &old_SIGABRT_action);
274
275 int result = 0;
276 bool trapped_signal = false;
277 char const *em = NULL;
278
279 volatile int sigtype = sigsetjmp(jump_buf, 1);
280
281 if(sigtype == 0)
282 {
283 result = cpp_main(argc, argv);
284 }
285
286 else
287 {
288 trapped_signal = true;
289 switch(sigtype)
290 {
291 case SIGTRAP:
292 em = "signal: SIGTRAP (perhaps integer divide by zero)";
293 break;
294 case SIGFPE:
295 em = "signal: SIGFPE (arithmetic exception)";
296 break;
297 case SIGABRT:
298 em = "signal: SIGABRT (application abort requested)";
299 break;
300 case SIGSEGV:
301 case SIGBUS:
302 em = "signal: memory access violation";
303 break;
304 default:
305 em = "signal: unrecognized signal";
306 }
307 }
308
309 sigaction(SIGFPE , &old_SIGFPE_action , sigaction_ptr());
310 sigaction(SIGTRAP, &old_SIGTRAP_action, sigaction_ptr());
311 sigaction(SIGSEGV, &old_SIGSEGV_action, sigaction_ptr());
312 sigaction(SIGBUS , &old_SIGBUS_action , sigaction_ptr());
313 sigaction(SIGABRT, &old_SIGABRT_action, sigaction_ptr());
314
315 if(trapped_signal)
316 throw unix_signal_exception(em);
317
318 return result;
319}
320#endif
321
322
323static int
324main_with_many_flavours_of_exception(int argc, char **argv)
325{
326
327#if defined(MS_STRUCTURED_EXCEPTION_HANDLING) && !defined(__BORLANDC__) && !defined(__MINGW32__)
328 _set_se_translator(ms_se_trans_func);
329#endif
330
331#if defined(MS_CRT_DEBUG_HOOK)
332 _CrtSetReportHook(&assert_reporting_function);
333#endif
334
335 try
336 {
337 return main_with_signal_handlers(argc, argv);
338 }
339
340 catch (char const * ex)
341 {
342 report_error("C string: ", ex);
343 }
344
345 catch (std::string const & ex)
346 {
347 report_error("std::string: ", ex.c_str());
348 }
349
350 catch( std::bad_alloc const & ex )
351 {
352 report_error("std::bad_alloc: ", ex.what());
353 }
354
355#if !defined(__BORLANDC__) || __BORLANDC__ > 0x0551
356 catch (std::bad_cast const & ex)
357 {
358 report_error("std::bad_cast: ", ex.what());
359 }
360
361 catch (std::bad_typeid const & ex)
362 {
363 report_error("std::bad_typeid: ", ex.what());
364 }
365#else
366 catch(std::bad_cast const & ex)
367 {
368 report_error("std::bad_cast");
369 }
370
371 catch( std::bad_typeid const & ex)
372 {
373 report_error("std::bad_typeid");
374 }
375#endif
376
377 catch(std::bad_exception const & ex)
378 {
379 report_error("std::bad_exception: ", ex.what());
380 }
381
382 catch( std::domain_error const& ex )
383 {
384 report_error("std::domain_error: ", ex.what());
385 }
386
387 catch( std::invalid_argument const& ex )
388 {
389 report_error("std::invalid_argument: ", ex.what());
390 }
391
392 catch( std::length_error const& ex )
393 {
394 report_error("std::length_error: ", ex.what());
395 }
396
397 catch( std::out_of_range const& ex )
398 {
399 report_error("std::out_of_range: ", ex.what());
400 }
401
402 catch( std::range_error const& ex )
403 {
404 report_error("std::range_error: ", ex.what());
405 }
406
407 catch( std::overflow_error const& ex )
408 {
409 report_error("std::overflow_error: ", ex.what());
410 }
411
412 catch( std::underflow_error const& ex )
413 {
414 report_error("std::underflow_error: ", ex.what());
415 }
416
417 catch( std::logic_error const& ex )
418 {
419 report_error("std::logic_error: ", ex.what());
420 }
421
422 catch( std::runtime_error const& ex )
423 {
424 report_error("std::runtime_error: ", ex.what());
425 }
426
427 catch( std::exception const& ex )
428 {
429 report_error("std::exception: ", ex.what());
430 }
431
432#if defined(MS_STRUCTURED_EXCEPTION_HANDLING)
433 catch(ms_se_exception const & ex)
434 {
435 report_ms_se_error(ex.exception_id);
436 }
437
438#elif defined(UNIX_STYLE_SIGNAL_HANDLING)
439 catch(unix_signal_exception const & ex)
440 {
441 report_error(ex.error_message);
442 }
443#endif
444
445 catch( ... )
446 {
447 report_error("unknown type" );
448 }
449 return 0;
450}
451
452int
453main(int argc, char **argv)
454{
455 try
456 {
457 return main_with_many_flavours_of_exception(argc, argv);
458 }
459 catch (the_one_true_exception const & e)
460 {
461 ui.fatal(std::string(e.buf) + "\n");
462 // If we got here, it's because something went _really_ wrong, like an
463 // invariant failure or a segfault. So use a distinctive error code, in
464 // particular so the testsuite can tell whether we detected an error
465 // properly or waited until an invariant caught it...
466 return 3;
467 }
468}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status