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

Archive Download this file

Branches

Tags

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