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

Archive Download this file

Branches

Tags

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