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

Archive Download this file

Branches

Tags

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