1 | // (C) Copyright Gennadiy Rozental 2001. |
2 | // (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001. |
3 | // Use, modification, and distribution are subject to the |
4 | // Boost Software License, Version 1.0. (See accompanying file |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | |
7 | // See http://www.boost.org/libs/test for the library home page. |
8 | // |
9 | // File : $RCSfile$ |
10 | // |
11 | // Version : $Revision$ |
12 | // |
13 | // Description : provides execution monitor implementation for all supported |
14 | // configurations, including Microsoft structured exception based, unix signals |
15 | // based and special workarounds for borland |
16 | // |
17 | // Note that when testing requirements or user wishes preclude use of this |
18 | // file as a separate compilation unit, it may be included as a header file. |
19 | // |
20 | // Header dependencies are deliberately restricted to reduce coupling to other |
21 | // boost libraries. |
22 | // *************************************************************************** |
23 | |
24 | #ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER |
25 | #define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER |
26 | |
27 | // Boost.Test |
28 | #include <boost/test/detail/config.hpp> |
29 | #include <boost/test/detail/workaround.hpp> |
30 | #include <boost/test/detail/throw_exception.hpp> |
31 | #include <boost/test/execution_monitor.hpp> |
32 | #include <boost/test/debug.hpp> |
33 | |
34 | // Boost |
35 | #include <boost/cstdlib.hpp> // for exit codes |
36 | #include <boost/config.hpp> // for workarounds |
37 | #include <boost/core/ignore_unused.hpp> // for ignore_unused |
38 | #ifndef BOOST_NO_EXCEPTION |
39 | #include <boost/exception/get_error_info.hpp> // for get_error_info |
40 | #include <boost/exception/current_exception_cast.hpp> // for current_exception_cast |
41 | #endif |
42 | |
43 | // STL |
44 | #include <string> // for std::string |
45 | #include <new> // for std::bad_alloc |
46 | #include <typeinfo> // for std::bad_cast, std::bad_typeid |
47 | #include <exception> // for std::exception, std::bad_exception |
48 | #include <stdexcept> // for std exception hierarchy |
49 | #include <cstring> // for C string API |
50 | #include <cassert> // for assert |
51 | #include <cstddef> // for NULL |
52 | #include <cstdio> // for vsnprintf |
53 | #include <cstdarg> // for varargs |
54 | |
55 | #include <iostream> // for varargs |
56 | |
57 | #ifdef BOOST_NO_STDC_NAMESPACE |
58 | namespace std { using ::strerror; using ::strlen; using ::strncat; } |
59 | #endif |
60 | |
61 | // to use vsnprintf |
62 | #if defined(__SUNPRO_CC) || defined(__SunOS) |
63 | # include <stdio.h> |
64 | # include <stdarg.h> |
65 | using std::va_list; |
66 | #endif |
67 | |
68 | // to use vsnprintf |
69 | #if defined(__QNXNTO__) |
70 | # include <stdio.h> |
71 | #endif |
72 | |
73 | #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING |
74 | # include <windows.h> |
75 | |
76 | # if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) |
77 | # include <eh.h> |
78 | # endif |
79 | |
80 | # if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 || defined(__MWERKS__) |
81 | # include <stdint.h> |
82 | # endif |
83 | |
84 | # if defined(__BORLANDC__) && __BORLANDC__ < 0x560 |
85 | typedef unsigned uintptr_t; |
86 | # endif |
87 | |
88 | # if defined(UNDER_CE) && BOOST_WORKAROUND(_MSC_VER, < 1500 ) |
89 | typedef void* uintptr_t; |
90 | # elif defined(UNDER_CE) |
91 | # include <crtdefs.h> |
92 | # endif |
93 | |
94 | # if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE) |
95 | # include <crtdbg.h> |
96 | # define BOOST_TEST_CRT_HOOK_TYPE _CRT_REPORT_HOOK |
97 | # define BOOST_TEST_CRT_ASSERT _CRT_ASSERT |
98 | # define BOOST_TEST_CRT_ERROR _CRT_ERROR |
99 | # define BOOST_TEST_CRT_SET_HOOK(H) _CrtSetReportHook(H) |
100 | # else |
101 | # define BOOST_TEST_CRT_HOOK_TYPE void* |
102 | # define BOOST_TEST_CRT_ASSERT 2 |
103 | # define BOOST_TEST_CRT_ERROR 1 |
104 | # define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H) |
105 | # endif |
106 | |
107 | # if (!BOOST_WORKAROUND(_MSC_VER, >= 1400 ) && \ |
108 | !defined(BOOST_COMO)) || defined(UNDER_CE) |
109 | |
110 | typedef void* _invalid_parameter_handler; |
111 | |
112 | inline _invalid_parameter_handler |
113 | _set_invalid_parameter_handler( _invalid_parameter_handler arg ) |
114 | { |
115 | return arg; |
116 | } |
117 | |
118 | # endif |
119 | |
120 | # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE) |
121 | |
122 | namespace { void _set_se_translator( void* ) {} } |
123 | |
124 | # endif |
125 | |
126 | #elif defined(BOOST_HAS_SIGACTION) |
127 | |
128 | # define BOOST_SIGACTION_BASED_SIGNAL_HANDLING |
129 | |
130 | # include <unistd.h> |
131 | # include <signal.h> |
132 | # include <setjmp.h> |
133 | |
134 | # if defined(__FreeBSD__) |
135 | |
136 | # include <osreldate.h> |
137 | |
138 | # ifndef SIGPOLL |
139 | # define SIGPOLL SIGIO |
140 | # endif |
141 | |
142 | # if (__FreeBSD_version < 70100) |
143 | |
144 | # define ILL_ILLADR 0 // ILL_RESAD_FAULT |
145 | # define ILL_PRVOPC ILL_PRIVIN_FAULT |
146 | # define ILL_ILLOPN 2 // ILL_RESOP_FAULT |
147 | # define ILL_COPROC ILL_FPOP_FAULT |
148 | |
149 | # define BOOST_TEST_LIMITED_SIGNAL_DETAILS |
150 | |
151 | # endif |
152 | # endif |
153 | |
154 | # if defined(__ANDROID__) |
155 | # include <android/api-level.h> |
156 | # endif |
157 | |
158 | # if !defined(__CYGWIN__) && !defined(__QNXNTO__) && !defined(__bgq__) && \ |
159 | (!defined(__ANDROID__) || __ANDROID_API__ >= 8) |
160 | # define BOOST_TEST_USE_ALT_STACK |
161 | # endif |
162 | |
163 | # if defined(SIGPOLL) && !defined(__CYGWIN__) && \ |
164 | !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && \ |
165 | !defined(__NetBSD__) && \ |
166 | !defined(__QNXNTO__) |
167 | # define BOOST_TEST_CATCH_SIGPOLL |
168 | # endif |
169 | |
170 | # ifdef BOOST_TEST_USE_ALT_STACK |
171 | # define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ |
172 | # endif |
173 | |
174 | |
175 | #else |
176 | |
177 | # define BOOST_NO_SIGNAL_HANDLING |
178 | |
179 | #endif |
180 | |
181 | #ifndef UNDER_CE |
182 | #include <errno.h> |
183 | #endif |
184 | |
185 | #if defined(__GNUC__) && !defined(BOOST_NO_TYPEID) |
186 | # include <cxxabi.h> |
187 | #endif |
188 | |
189 | #include <boost/test/detail/suppress_warnings.hpp> |
190 | |
191 | //____________________________________________________________________________// |
192 | |
193 | namespace boost { |
194 | |
195 | // ************************************************************************** // |
196 | // ************** throw_exception ************** // |
197 | // ************************************************************************** // |
198 | |
199 | #ifdef BOOST_NO_EXCEPTION |
200 | void throw_exception( std::exception const & e ) { abort(); } |
201 | #endif |
202 | |
203 | // ************************************************************************** // |
204 | // ************** report_error ************** // |
205 | // ************************************************************************** // |
206 | |
207 | namespace detail { |
208 | |
209 | #ifdef __BORLANDC__ |
210 | # define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) ) |
211 | #elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \ |
212 | BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \ |
213 | defined(UNDER_CE) |
214 | # define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) ) |
215 | #else |
216 | # define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) ) |
217 | #endif |
218 | |
219 | #ifndef BOOST_NO_EXCEPTION |
220 | |
221 | template <typename ErrorInfo> |
222 | typename ErrorInfo::value_type |
223 | ( boost::exception const* ex ) |
224 | { |
225 | if( !ex ) |
226 | return 0; |
227 | |
228 | typename ErrorInfo::value_type const * val = boost::get_error_info<ErrorInfo>( *ex ); |
229 | |
230 | return val ? *val : 0; |
231 | } |
232 | |
233 | //____________________________________________________________________________// |
234 | |
235 | static void |
236 | report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, va_list* args ) |
237 | { |
238 | static const int REPORT_ERROR_BUFFER_SIZE = 4096; |
239 | static char buf[REPORT_ERROR_BUFFER_SIZE]; |
240 | |
241 | BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); |
242 | buf[sizeof(buf)-1] = 0; |
243 | |
244 | va_end( *args ); |
245 | |
246 | BOOST_TEST_I_THROW(execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ), |
247 | (size_t)extract<throw_line>( be ), |
248 | extract<throw_function>( be ) ) )); |
249 | } |
250 | |
251 | //____________________________________________________________________________// |
252 | |
253 | static void |
254 | report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) |
255 | { |
256 | va_list args; |
257 | va_start( args, format ); |
258 | |
259 | report_error( ec, be, format, args: &args ); |
260 | } |
261 | |
262 | #endif |
263 | |
264 | //____________________________________________________________________________// |
265 | |
266 | static void |
267 | report_error( execution_exception::error_code ec, char const* format, ... ) |
268 | { |
269 | va_list args; |
270 | va_start( args, format ); |
271 | |
272 | report_error( ec, be: 0, format, args: &args ); |
273 | } |
274 | |
275 | //____________________________________________________________________________// |
276 | |
277 | template<typename Tr,typename Functor> |
278 | inline int |
279 | do_invoke( Tr const& tr, Functor const& F ) |
280 | { |
281 | return tr ? (*tr)( F ) : F(); |
282 | } |
283 | |
284 | //____________________________________________________________________________// |
285 | |
286 | struct fpe_except_guard { |
287 | explicit fpe_except_guard( unsigned detect_fpe ) |
288 | : m_detect_fpe( detect_fpe ) |
289 | { |
290 | // prepare fp exceptions control |
291 | m_previosly_enabled = fpe::disable( mask: fpe::BOOST_FPE_ALL ); |
292 | if( m_previosly_enabled != fpe::BOOST_FPE_INV && detect_fpe != fpe::BOOST_FPE_OFF ) |
293 | fpe::enable( mask: detect_fpe ); |
294 | } |
295 | ~fpe_except_guard() |
296 | { |
297 | if( m_detect_fpe != fpe::BOOST_FPE_OFF ) |
298 | fpe::disable( mask: m_detect_fpe ); |
299 | if( m_previosly_enabled != fpe::BOOST_FPE_INV ) |
300 | fpe::enable( mask: m_previosly_enabled ); |
301 | } |
302 | |
303 | unsigned m_detect_fpe; |
304 | unsigned m_previosly_enabled; |
305 | }; |
306 | |
307 | #ifndef BOOST_NO_TYPEID |
308 | |
309 | // ************************************************************************** // |
310 | // ************** typeid_name ************** // |
311 | // ************************************************************************** // |
312 | |
313 | template<typename T> |
314 | char const* |
315 | typeid_name( T const& t ) |
316 | { |
317 | #ifdef __GNUC__ |
318 | int status; |
319 | |
320 | return abi::__cxa_demangle( mangled_name: typeid(t).name(), output_buffer: 0, length: 0, status: &status ); |
321 | #else |
322 | return typeid(t).name(); |
323 | #endif |
324 | } |
325 | #endif |
326 | |
327 | } // namespace detail |
328 | |
329 | #if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) |
330 | |
331 | // ************************************************************************** // |
332 | // ************** Sigaction based signal handling ************** // |
333 | // ************************************************************************** // |
334 | |
335 | namespace detail { |
336 | |
337 | // ************************************************************************** // |
338 | // ************** boost::detail::system_signal_exception ************** // |
339 | // ************************************************************************** // |
340 | |
341 | class system_signal_exception { |
342 | public: |
343 | // Constructor |
344 | system_signal_exception() |
345 | : m_sig_info( 0 ) |
346 | , m_context( 0 ) |
347 | {} |
348 | |
349 | // Access methods |
350 | void operator()( siginfo_t* i, void* c ) |
351 | { |
352 | m_sig_info = i; |
353 | m_context = c; |
354 | } |
355 | void report() const; |
356 | |
357 | private: |
358 | // Data members |
359 | siginfo_t* m_sig_info; // system signal detailed info |
360 | void* m_context; // signal context |
361 | }; |
362 | |
363 | //____________________________________________________________________________// |
364 | |
365 | void |
366 | system_signal_exception::report() const |
367 | { |
368 | if( !m_sig_info ) |
369 | return; // no error actually occur? |
370 | |
371 | switch( m_sig_info->si_code ) { |
372 | case SI_USER: |
373 | report_error( ec: execution_exception::system_error, |
374 | format: "signal: generated by kill() (or family); uid=%d; pid=%d" , |
375 | (int)m_sig_info->si_uid, (int)m_sig_info->si_pid ); |
376 | break; |
377 | case SI_QUEUE: |
378 | report_error( ec: execution_exception::system_error, |
379 | format: "signal: sent by sigqueue()" ); |
380 | break; |
381 | case SI_TIMER: |
382 | report_error( ec: execution_exception::system_error, |
383 | format: "signal: the expiration of a timer set by timer_settimer()" ); |
384 | break; |
385 | case SI_ASYNCIO: |
386 | report_error( ec: execution_exception::system_error, |
387 | format: "signal: generated by the completion of an asynchronous I/O request" ); |
388 | break; |
389 | case SI_MESGQ: |
390 | report_error( ec: execution_exception::system_error, |
391 | format: "signal: generated by the the arrival of a message on an empty message queue" ); |
392 | break; |
393 | default: |
394 | break; |
395 | } |
396 | |
397 | switch( m_sig_info->si_signo ) { |
398 | case SIGILL: |
399 | switch( m_sig_info->si_code ) { |
400 | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS |
401 | case ILL_ILLOPC: |
402 | report_error( ec: execution_exception::system_fatal_error, |
403 | format: "signal: illegal opcode; address of failing instruction: 0x%08lx" , |
404 | m_sig_info->si_addr ); |
405 | break; |
406 | case ILL_ILLTRP: |
407 | report_error( ec: execution_exception::system_fatal_error, |
408 | format: "signal: illegal trap; address of failing instruction: 0x%08lx" , |
409 | m_sig_info->si_addr ); |
410 | break; |
411 | case ILL_PRVREG: |
412 | report_error( ec: execution_exception::system_fatal_error, |
413 | format: "signal: privileged register; address of failing instruction: 0x%08lx" , |
414 | m_sig_info->si_addr ); |
415 | break; |
416 | case ILL_BADSTK: |
417 | report_error( ec: execution_exception::system_fatal_error, |
418 | format: "signal: internal stack error; address of failing instruction: 0x%08lx" , |
419 | m_sig_info->si_addr ); |
420 | break; |
421 | #endif |
422 | case ILL_ILLOPN: |
423 | report_error( ec: execution_exception::system_fatal_error, |
424 | format: "signal: illegal operand; address of failing instruction: 0x%08lx" , |
425 | m_sig_info->si_addr ); |
426 | break; |
427 | case ILL_ILLADR: |
428 | report_error( ec: execution_exception::system_fatal_error, |
429 | format: "signal: illegal addressing mode; address of failing instruction: 0x%08lx" , |
430 | m_sig_info->si_addr ); |
431 | break; |
432 | case ILL_PRVOPC: |
433 | report_error( ec: execution_exception::system_fatal_error, |
434 | format: "signal: privileged opcode; address of failing instruction: 0x%08lx" , |
435 | m_sig_info->si_addr ); |
436 | break; |
437 | case ILL_COPROC: |
438 | report_error( ec: execution_exception::system_fatal_error, |
439 | format: "signal: co-processor error; address of failing instruction: 0x%08lx" , |
440 | m_sig_info->si_addr ); |
441 | break; |
442 | default: |
443 | report_error( ec: execution_exception::system_fatal_error, |
444 | format: "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)" , |
445 | m_sig_info->si_addr, m_sig_info->si_code ); |
446 | break; |
447 | } |
448 | break; |
449 | |
450 | case SIGFPE: |
451 | switch( m_sig_info->si_code ) { |
452 | case FPE_INTDIV: |
453 | report_error( ec: execution_exception::system_error, |
454 | format: "signal: integer divide by zero; address of failing instruction: 0x%08lx" , |
455 | m_sig_info->si_addr ); |
456 | break; |
457 | case FPE_INTOVF: |
458 | report_error( ec: execution_exception::system_error, |
459 | format: "signal: integer overflow; address of failing instruction: 0x%08lx" , |
460 | m_sig_info->si_addr ); |
461 | break; |
462 | case FPE_FLTDIV: |
463 | report_error( ec: execution_exception::system_error, |
464 | format: "signal: floating point divide by zero; address of failing instruction: 0x%08lx" , |
465 | m_sig_info->si_addr ); |
466 | break; |
467 | case FPE_FLTOVF: |
468 | report_error( ec: execution_exception::system_error, |
469 | format: "signal: floating point overflow; address of failing instruction: 0x%08lx" , |
470 | m_sig_info->si_addr ); |
471 | break; |
472 | case FPE_FLTUND: |
473 | report_error( ec: execution_exception::system_error, |
474 | format: "signal: floating point underflow; address of failing instruction: 0x%08lx" , |
475 | m_sig_info->si_addr ); |
476 | break; |
477 | case FPE_FLTRES: |
478 | report_error( ec: execution_exception::system_error, |
479 | format: "signal: floating point inexact result; address of failing instruction: 0x%08lx" , |
480 | m_sig_info->si_addr ); |
481 | break; |
482 | case FPE_FLTINV: |
483 | report_error( ec: execution_exception::system_error, |
484 | format: "signal: invalid floating point operation; address of failing instruction: 0x%08lx" , |
485 | m_sig_info->si_addr ); |
486 | break; |
487 | case FPE_FLTSUB: |
488 | report_error( ec: execution_exception::system_error, |
489 | format: "signal: subscript out of range; address of failing instruction: 0x%08lx" , |
490 | m_sig_info->si_addr ); |
491 | break; |
492 | default: |
493 | report_error( ec: execution_exception::system_error, |
494 | format: "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)" , |
495 | m_sig_info->si_addr, m_sig_info->si_code ); |
496 | break; |
497 | } |
498 | break; |
499 | |
500 | case SIGSEGV: |
501 | switch( m_sig_info->si_code ) { |
502 | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS |
503 | case SEGV_MAPERR: |
504 | report_error( ec: execution_exception::system_fatal_error, |
505 | format: "memory access violation at address: 0x%08lx: no mapping at fault address" , |
506 | m_sig_info->si_addr ); |
507 | break; |
508 | case SEGV_ACCERR: |
509 | report_error( ec: execution_exception::system_fatal_error, |
510 | format: "memory access violation at address: 0x%08lx: invalid permissions" , |
511 | m_sig_info->si_addr ); |
512 | break; |
513 | #endif |
514 | default: |
515 | report_error( ec: execution_exception::system_fatal_error, |
516 | format: "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)" , |
517 | m_sig_info->si_addr, m_sig_info->si_code ); |
518 | break; |
519 | } |
520 | break; |
521 | |
522 | case SIGBUS: |
523 | switch( m_sig_info->si_code ) { |
524 | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS |
525 | case BUS_ADRALN: |
526 | report_error( ec: execution_exception::system_fatal_error, |
527 | format: "memory access violation at address: 0x%08lx: invalid address alignment" , |
528 | m_sig_info->si_addr ); |
529 | break; |
530 | case BUS_ADRERR: |
531 | report_error( ec: execution_exception::system_fatal_error, |
532 | format: "memory access violation at address: 0x%08lx: non-existent physical address" , |
533 | m_sig_info->si_addr ); |
534 | break; |
535 | case BUS_OBJERR: |
536 | report_error( ec: execution_exception::system_fatal_error, |
537 | format: "memory access violation at address: 0x%08lx: object specific hardware error" , |
538 | m_sig_info->si_addr ); |
539 | break; |
540 | #endif |
541 | default: |
542 | report_error( ec: execution_exception::system_fatal_error, |
543 | format: "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)" , |
544 | m_sig_info->si_addr, m_sig_info->si_code ); |
545 | break; |
546 | } |
547 | break; |
548 | |
549 | #if defined(BOOST_TEST_CATCH_SIGPOLL) |
550 | |
551 | case SIGPOLL: |
552 | switch( m_sig_info->si_code ) { |
553 | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS |
554 | case POLL_IN: |
555 | report_error( ec: execution_exception::system_error, |
556 | format: "data input available; band event %d" , |
557 | (int)m_sig_info->si_band ); |
558 | break; |
559 | case POLL_OUT: |
560 | report_error( ec: execution_exception::system_error, |
561 | format: "output buffers available; band event %d" , |
562 | (int)m_sig_info->si_band ); |
563 | break; |
564 | case POLL_MSG: |
565 | report_error( ec: execution_exception::system_error, |
566 | format: "input message available; band event %d" , |
567 | (int)m_sig_info->si_band ); |
568 | break; |
569 | case POLL_ERR: |
570 | report_error( ec: execution_exception::system_error, |
571 | format: "i/o error; band event %d" , |
572 | (int)m_sig_info->si_band ); |
573 | break; |
574 | case POLL_PRI: |
575 | report_error( ec: execution_exception::system_error, |
576 | format: "high priority input available; band event %d" , |
577 | (int)m_sig_info->si_band ); |
578 | break; |
579 | #if defined(POLL_ERR) && defined(POLL_HUP) && (POLL_ERR - POLL_HUP) |
580 | case POLL_HUP: |
581 | report_error( execution_exception::system_error, |
582 | "device disconnected; band event %d" , |
583 | (int)m_sig_info->si_band ); |
584 | break; |
585 | #endif |
586 | #endif |
587 | default: |
588 | report_error( ec: execution_exception::system_error, |
589 | format: "signal: SIGPOLL, si_code: %d (asynchronous I/O event occurred; band event %d)" , |
590 | (int)m_sig_info->si_band, m_sig_info->si_code ); |
591 | break; |
592 | } |
593 | break; |
594 | |
595 | #endif |
596 | |
597 | case SIGABRT: |
598 | report_error( ec: execution_exception::system_error, |
599 | format: "signal: SIGABRT (application abort requested)" ); |
600 | break; |
601 | |
602 | case SIGALRM: |
603 | report_error( ec: execution_exception::timeout_error, |
604 | format: "signal: SIGALRM (timeout while executing function)" ); |
605 | break; |
606 | |
607 | default: |
608 | report_error( ec: execution_exception::system_error, |
609 | format: "unrecognized signal %d" , m_sig_info->si_signo ); |
610 | } |
611 | } |
612 | |
613 | //____________________________________________________________________________// |
614 | |
615 | // ************************************************************************** // |
616 | // ************** boost::detail::signal_action ************** // |
617 | // ************************************************************************** // |
618 | |
619 | // Forward declaration |
620 | extern "C" { |
621 | static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); |
622 | static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); |
623 | } |
624 | |
625 | class signal_action { |
626 | typedef struct sigaction* sigaction_ptr; |
627 | public: |
628 | //Constructor |
629 | signal_action(); |
630 | signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ); |
631 | ~signal_action(); |
632 | |
633 | private: |
634 | // Data members |
635 | int m_sig; |
636 | bool m_installed; |
637 | struct sigaction m_new_action; |
638 | struct sigaction m_old_action; |
639 | }; |
640 | |
641 | //____________________________________________________________________________// |
642 | |
643 | signal_action::signal_action() |
644 | : m_installed( false ) |
645 | {} |
646 | |
647 | //____________________________________________________________________________// |
648 | |
649 | signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ) |
650 | : m_sig( sig ) |
651 | , m_installed( install ) |
652 | { |
653 | if( !install ) |
654 | return; |
655 | |
656 | std::memset( s: &m_new_action, c: 0, n: sizeof(struct sigaction) ); |
657 | |
658 | BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig , sigaction_ptr(), &m_new_action ) != -1 ); |
659 | |
660 | if( m_new_action.sa_sigaction || m_new_action.sa_handler ) { |
661 | m_installed = false; |
662 | return; |
663 | } |
664 | |
665 | m_new_action.sa_flags |= SA_SIGINFO; |
666 | m_new_action.sa_sigaction = attach_dbg ? &boost_execution_monitor_attaching_signal_handler |
667 | : &boost_execution_monitor_jumping_signal_handler; |
668 | BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 ); |
669 | |
670 | #ifdef BOOST_TEST_USE_ALT_STACK |
671 | if( alt_stack ) |
672 | m_new_action.sa_flags |= SA_ONSTACK; |
673 | #endif |
674 | |
675 | BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig, &m_new_action, &m_old_action ) != -1 ); |
676 | } |
677 | |
678 | //____________________________________________________________________________// |
679 | |
680 | signal_action::~signal_action() |
681 | { |
682 | if( m_installed ) |
683 | ::sigaction( sig: m_sig, act: &m_old_action , oact: sigaction_ptr() ); |
684 | } |
685 | |
686 | //____________________________________________________________________________// |
687 | |
688 | // ************************************************************************** // |
689 | // ************** boost::detail::signal_handler ************** // |
690 | // ************************************************************************** // |
691 | |
692 | class signal_handler { |
693 | public: |
694 | // Constructor |
695 | explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ); |
696 | |
697 | // Destructor |
698 | ~signal_handler(); |
699 | |
700 | // access methods |
701 | static sigjmp_buf& jump_buffer() |
702 | { |
703 | assert( !!s_active_handler ); |
704 | |
705 | return s_active_handler->m_sigjmp_buf; |
706 | } |
707 | |
708 | static system_signal_exception& sys_sig() |
709 | { |
710 | assert( !!s_active_handler ); |
711 | |
712 | return s_active_handler->m_sys_sig; |
713 | } |
714 | |
715 | private: |
716 | // Data members |
717 | signal_handler* m_prev_handler; |
718 | unsigned m_timeout; |
719 | |
720 | // Note: We intentionality do not catch SIGCHLD. Users have to deal with it themselves |
721 | signal_action m_ILL_action; |
722 | signal_action m_FPE_action; |
723 | signal_action m_SEGV_action; |
724 | signal_action m_BUS_action; |
725 | signal_action m_CHLD_action; |
726 | signal_action m_POLL_action; |
727 | signal_action m_ABRT_action; |
728 | signal_action m_ALRM_action; |
729 | |
730 | sigjmp_buf m_sigjmp_buf; |
731 | system_signal_exception m_sys_sig; |
732 | |
733 | static signal_handler* s_active_handler; |
734 | }; |
735 | |
736 | // !! need to be placed in thread specific storage |
737 | typedef signal_handler* signal_handler_ptr; |
738 | signal_handler* signal_handler::s_active_handler = signal_handler_ptr(); |
739 | |
740 | //____________________________________________________________________________// |
741 | |
742 | signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ) |
743 | : m_prev_handler( s_active_handler ) |
744 | , m_timeout( timeout ) |
745 | , m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack ) |
746 | , m_FPE_action ( SIGFPE , detect_fpe , attach_dbg, alt_stack ) |
747 | , m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack ) |
748 | , m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack ) |
749 | #ifdef BOOST_TEST_CATCH_SIGPOLL |
750 | , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) |
751 | #endif |
752 | , m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack ) |
753 | , m_ALRM_action( SIGALRM, timeout > 0 , attach_dbg, alt_stack ) |
754 | { |
755 | s_active_handler = this; |
756 | |
757 | if( m_timeout > 0 ) { |
758 | ::alarm( seconds: 0 ); |
759 | ::alarm( seconds: timeout ); |
760 | } |
761 | |
762 | #ifdef BOOST_TEST_USE_ALT_STACK |
763 | if( alt_stack ) { |
764 | stack_t sigstk; |
765 | std::memset( s: &sigstk, c: 0, n: sizeof(stack_t) ); |
766 | |
767 | BOOST_TEST_SYS_ASSERT( ::sigaltstack( 0, &sigstk ) != -1 ); |
768 | |
769 | if( sigstk.ss_flags & SS_DISABLE ) { |
770 | sigstk.ss_sp = alt_stack; |
771 | sigstk.ss_size = BOOST_TEST_ALT_STACK_SIZE; |
772 | sigstk.ss_flags = 0; |
773 | BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); |
774 | } |
775 | } |
776 | #endif |
777 | } |
778 | |
779 | //____________________________________________________________________________// |
780 | |
781 | signal_handler::~signal_handler() |
782 | { |
783 | assert( s_active_handler == this ); |
784 | |
785 | if( m_timeout > 0 ) |
786 | ::alarm( seconds: 0 ); |
787 | |
788 | #ifdef BOOST_TEST_USE_ALT_STACK |
789 | #ifdef __GNUC__ |
790 | // We shouldn't need to explicitly initialize all the members here, |
791 | // but gcc warns if we don't, so add initializers for each of the |
792 | // members specified in the POSIX std: |
793 | stack_t sigstk = { .ss_sp: 0, .ss_flags: 0, .ss_size: 0 }; |
794 | #else |
795 | stack_t sigstk = { }; |
796 | #endif |
797 | |
798 | sigstk.ss_size = MINSIGSTKSZ; |
799 | sigstk.ss_flags = SS_DISABLE; |
800 | if( ::sigaltstack( ss: &sigstk, oss: 0 ) == -1 ) { |
801 | int error_n = errno; |
802 | std::cerr << "******** errors disabling the alternate stack:" << std::endl |
803 | << "\t#error:" << error_n << std::endl |
804 | << "\t" << std::strerror( errnum: error_n ) << std::endl; |
805 | } |
806 | #endif |
807 | |
808 | s_active_handler = m_prev_handler; |
809 | } |
810 | |
811 | //____________________________________________________________________________// |
812 | |
813 | // ************************************************************************** // |
814 | // ************** execution_monitor_signal_handler ************** // |
815 | // ************************************************************************** // |
816 | |
817 | extern "C" { |
818 | |
819 | static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) |
820 | { |
821 | signal_handler::sys_sig()( info, context ); |
822 | |
823 | siglongjmp( env: signal_handler::jump_buffer(), val: sig ); |
824 | } |
825 | |
826 | //____________________________________________________________________________// |
827 | |
828 | static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) |
829 | { |
830 | if( !debug::attach_debugger( break_or_continue: false ) ) |
831 | boost_execution_monitor_jumping_signal_handler( sig, info, context ); |
832 | |
833 | // debugger attached; it will handle the signal |
834 | BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR ); |
835 | } |
836 | |
837 | //____________________________________________________________________________// |
838 | |
839 | } |
840 | |
841 | } // namespace detail |
842 | |
843 | // ************************************************************************** // |
844 | // ************** execution_monitor::catch_signals ************** // |
845 | // ************************************************************************** // |
846 | |
847 | int |
848 | execution_monitor::catch_signals( boost::function<int ()> const& F ) |
849 | { |
850 | using namespace detail; |
851 | |
852 | #if defined(__CYGWIN__) |
853 | p_catch_system_errors.value = false; |
854 | #endif |
855 | |
856 | #ifdef BOOST_TEST_USE_ALT_STACK |
857 | if( !!p_use_alt_stack && !m_alt_stack ) |
858 | m_alt_stack.reset( p: new char[BOOST_TEST_ALT_STACK_SIZE] ); |
859 | #else |
860 | p_use_alt_stack.value = false; |
861 | #endif |
862 | |
863 | signal_handler local_signal_handler( p_catch_system_errors, |
864 | p_catch_system_errors || (p_detect_fp_exceptions != fpe::BOOST_FPE_OFF), |
865 | p_timeout, |
866 | p_auto_start_dbg, |
867 | !p_use_alt_stack ? 0 : m_alt_stack.get() ); |
868 | |
869 | if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) ) |
870 | return detail::do_invoke( tr: m_custom_translators , F ); |
871 | else |
872 | BOOST_TEST_I_THROW( local_signal_handler.sys_sig() ); |
873 | } |
874 | |
875 | //____________________________________________________________________________// |
876 | |
877 | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) |
878 | |
879 | // ************************************************************************** // |
880 | // ************** Microsoft structured exception handling ************** // |
881 | // ************************************************************************** // |
882 | |
883 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) |
884 | namespace { void _set_se_translator( void* ) {} } |
885 | #endif |
886 | |
887 | namespace detail { |
888 | |
889 | // ************************************************************************** // |
890 | // ************** boost::detail::system_signal_exception ************** // |
891 | // ************************************************************************** // |
892 | |
893 | class system_signal_exception { |
894 | public: |
895 | // Constructor |
896 | explicit system_signal_exception( execution_monitor* em ) |
897 | : m_em( em ) |
898 | , m_se_id( 0 ) |
899 | , m_fault_address( 0 ) |
900 | , m_dir( false ) |
901 | {} |
902 | |
903 | void report() const; |
904 | int operator()( unsigned id, _EXCEPTION_POINTERS* exps ); |
905 | |
906 | private: |
907 | // Data members |
908 | execution_monitor* m_em; |
909 | |
910 | unsigned m_se_id; |
911 | void* m_fault_address; |
912 | bool m_dir; |
913 | }; |
914 | |
915 | //____________________________________________________________________________// |
916 | |
917 | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) |
918 | static void |
919 | seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ ) |
920 | { |
921 | throw; |
922 | } |
923 | #endif |
924 | |
925 | //____________________________________________________________________________// |
926 | |
927 | int |
928 | system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps ) |
929 | { |
930 | const unsigned MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC |
931 | |
932 | // C++ exception - allow to go through |
933 | if( id == MSFT_CPP_EXCEPT ) |
934 | return EXCEPTION_CONTINUE_SEARCH; |
935 | |
936 | // FPE detection is enabled, while system exception detection is not - check if this is actually FPE |
937 | if( !m_em->p_catch_system_errors ) { |
938 | if( !m_em->p_detect_fp_exceptions ) |
939 | return EXCEPTION_CONTINUE_SEARCH; |
940 | |
941 | switch( id ) { |
942 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: |
943 | case EXCEPTION_FLT_STACK_CHECK: |
944 | case EXCEPTION_FLT_DENORMAL_OPERAND: |
945 | case EXCEPTION_FLT_INEXACT_RESULT: |
946 | case EXCEPTION_FLT_OVERFLOW: |
947 | case EXCEPTION_FLT_UNDERFLOW: |
948 | case EXCEPTION_FLT_INVALID_OPERATION: |
949 | case STATUS_FLOAT_MULTIPLE_FAULTS: |
950 | case STATUS_FLOAT_MULTIPLE_TRAPS: |
951 | break; |
952 | default: |
953 | return EXCEPTION_CONTINUE_SEARCH; |
954 | } |
955 | } |
956 | |
957 | if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) { |
958 | m_em->p_catch_system_errors.value = false; |
959 | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) |
960 | _set_se_translator( &seh_catch_preventer ); |
961 | #endif |
962 | return EXCEPTION_CONTINUE_EXECUTION; |
963 | } |
964 | |
965 | m_se_id = id; |
966 | if( m_se_id == EXCEPTION_ACCESS_VIOLATION && exps->ExceptionRecord->NumberParameters == 2 ) { |
967 | m_fault_address = (void*)exps->ExceptionRecord->ExceptionInformation[1]; |
968 | m_dir = exps->ExceptionRecord->ExceptionInformation[0] == 0; |
969 | } |
970 | |
971 | return EXCEPTION_EXECUTE_HANDLER; |
972 | } |
973 | |
974 | //____________________________________________________________________________// |
975 | |
976 | void |
977 | system_signal_exception::report() const |
978 | { |
979 | switch( m_se_id ) { |
980 | // cases classified as system_fatal_error |
981 | case EXCEPTION_ACCESS_VIOLATION: { |
982 | if( !m_fault_address ) |
983 | detail::report_error( execution_exception::system_fatal_error, "memory access violation" ); |
984 | else |
985 | detail::report_error( |
986 | execution_exception::system_fatal_error, |
987 | "memory access violation occurred at address 0x%08lx, while attempting to %s" , |
988 | m_fault_address, |
989 | m_dir ? " read inaccessible data" |
990 | : " write to an inaccessible (or protected) address" |
991 | ); |
992 | break; |
993 | } |
994 | |
995 | case EXCEPTION_ILLEGAL_INSTRUCTION: |
996 | detail::report_error( execution_exception::system_fatal_error, "illegal instruction" ); |
997 | break; |
998 | |
999 | case EXCEPTION_PRIV_INSTRUCTION: |
1000 | detail::report_error( execution_exception::system_fatal_error, "tried to execute an instruction whose operation is not allowed in the current machine mode" ); |
1001 | break; |
1002 | |
1003 | case EXCEPTION_IN_PAGE_ERROR: |
1004 | detail::report_error( execution_exception::system_fatal_error, "access to a memory page that is not present" ); |
1005 | break; |
1006 | |
1007 | case EXCEPTION_STACK_OVERFLOW: |
1008 | detail::report_error( execution_exception::system_fatal_error, "stack overflow" ); |
1009 | break; |
1010 | |
1011 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: |
1012 | detail::report_error( execution_exception::system_fatal_error, "tried to continue execution after a non continuable exception occurred" ); |
1013 | break; |
1014 | |
1015 | // cases classified as (non-fatal) system_trap |
1016 | case EXCEPTION_DATATYPE_MISALIGNMENT: |
1017 | detail::report_error( execution_exception::system_error, "data misalignment" ); |
1018 | break; |
1019 | |
1020 | case EXCEPTION_INT_DIVIDE_BY_ZERO: |
1021 | detail::report_error( execution_exception::system_error, "integer divide by zero" ); |
1022 | break; |
1023 | |
1024 | case EXCEPTION_INT_OVERFLOW: |
1025 | detail::report_error( execution_exception::system_error, "integer overflow" ); |
1026 | break; |
1027 | |
1028 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: |
1029 | detail::report_error( execution_exception::system_error, "array bounds exceeded" ); |
1030 | break; |
1031 | |
1032 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: |
1033 | detail::report_error( execution_exception::system_error, "floating point divide by zero" ); |
1034 | break; |
1035 | |
1036 | case EXCEPTION_FLT_STACK_CHECK: |
1037 | detail::report_error( execution_exception::system_error, |
1038 | "stack overflowed or underflowed as the result of a floating-point operation" ); |
1039 | break; |
1040 | |
1041 | case EXCEPTION_FLT_DENORMAL_OPERAND: |
1042 | detail::report_error( execution_exception::system_error, |
1043 | "operand of floating point operation is denormal" ); |
1044 | break; |
1045 | |
1046 | case EXCEPTION_FLT_INEXACT_RESULT: |
1047 | detail::report_error( execution_exception::system_error, |
1048 | "result of a floating-point operation cannot be represented exactly" ); |
1049 | break; |
1050 | |
1051 | case EXCEPTION_FLT_OVERFLOW: |
1052 | detail::report_error( execution_exception::system_error, |
1053 | "exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type" ); |
1054 | break; |
1055 | |
1056 | case EXCEPTION_FLT_UNDERFLOW: |
1057 | detail::report_error( execution_exception::system_error, |
1058 | "exponent of a floating-point operation is less than the magnitude allowed by the corresponding type" ); |
1059 | break; |
1060 | |
1061 | case EXCEPTION_FLT_INVALID_OPERATION: |
1062 | detail::report_error( execution_exception::system_error, "floating point error" ); |
1063 | break; |
1064 | |
1065 | case STATUS_FLOAT_MULTIPLE_FAULTS: |
1066 | detail::report_error( execution_exception::system_error, "multiple floating point errors" ); |
1067 | break; |
1068 | |
1069 | case STATUS_FLOAT_MULTIPLE_TRAPS: |
1070 | detail::report_error( execution_exception::system_error, "multiple floating point errors" ); |
1071 | break; |
1072 | |
1073 | case EXCEPTION_BREAKPOINT: |
1074 | detail::report_error( execution_exception::system_error, "breakpoint encountered" ); |
1075 | break; |
1076 | |
1077 | default: |
1078 | detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx" , m_se_id ); |
1079 | break; |
1080 | } |
1081 | } |
1082 | |
1083 | //____________________________________________________________________________// |
1084 | |
1085 | // ************************************************************************** // |
1086 | // ************** assert_reporting_function ************** // |
1087 | // ************************************************************************** // |
1088 | |
1089 | int BOOST_TEST_CALL_DECL |
1090 | assert_reporting_function( int reportType, char* userMessage, int* ) |
1091 | { |
1092 | // write this way instead of switch to avoid unreachable statements |
1093 | if( reportType == BOOST_TEST_CRT_ASSERT || reportType == BOOST_TEST_CRT_ERROR ) |
1094 | detail::report_error( reportType == BOOST_TEST_CRT_ASSERT ? execution_exception::user_error : execution_exception::system_error, userMessage ); |
1095 | |
1096 | return 0; |
1097 | } // assert_reporting_function |
1098 | |
1099 | //____________________________________________________________________________// |
1100 | |
1101 | void BOOST_TEST_CALL_DECL |
1102 | invalid_param_handler( wchar_t const* /* expr */, |
1103 | wchar_t const* /* func */, |
1104 | wchar_t const* /* file */, |
1105 | unsigned /* line */, |
1106 | uintptr_t /* reserved */) |
1107 | { |
1108 | detail::report_error( execution_exception::user_error, |
1109 | "Invalid parameter detected by C runtime library" ); |
1110 | } |
1111 | |
1112 | //____________________________________________________________________________// |
1113 | |
1114 | } // namespace detail |
1115 | |
1116 | // ************************************************************************** // |
1117 | // ************** execution_monitor::catch_signals ************** // |
1118 | // ************************************************************************** // |
1119 | |
1120 | int |
1121 | execution_monitor::catch_signals( boost::function<int ()> const& F ) |
1122 | { |
1123 | _invalid_parameter_handler old_iph = _invalid_parameter_handler(); |
1124 | BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0; |
1125 | |
1126 | if( p_catch_system_errors ) { |
1127 | old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); |
1128 | |
1129 | old_iph = _set_invalid_parameter_handler( |
1130 | reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); |
1131 | } else if( !p_detect_fp_exceptions ) { |
1132 | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) |
1133 | _set_se_translator( &detail::seh_catch_preventer ); |
1134 | #endif |
1135 | } |
1136 | |
1137 | detail::system_signal_exception SSE( this ); |
1138 | |
1139 | int ret_val = 0; |
1140 | |
1141 | __try { |
1142 | __try { |
1143 | ret_val = detail::do_invoke( m_custom_translators, F ); |
1144 | } |
1145 | __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) { |
1146 | throw SSE; |
1147 | } |
1148 | } |
1149 | __finally { |
1150 | if( p_catch_system_errors ) { |
1151 | BOOST_TEST_CRT_SET_HOOK( old_crt_hook ); |
1152 | |
1153 | _set_invalid_parameter_handler( old_iph ); |
1154 | } |
1155 | } |
1156 | |
1157 | return ret_val; |
1158 | } |
1159 | |
1160 | //____________________________________________________________________________// |
1161 | |
1162 | #else // default signal handler |
1163 | |
1164 | namespace detail { |
1165 | |
1166 | class system_signal_exception { |
1167 | public: |
1168 | void report() const {} |
1169 | }; |
1170 | |
1171 | } // namespace detail |
1172 | |
1173 | int |
1174 | execution_monitor::catch_signals( boost::function<int ()> const& F ) |
1175 | { |
1176 | return detail::do_invoke( m_custom_translators , F ); |
1177 | } |
1178 | |
1179 | //____________________________________________________________________________// |
1180 | |
1181 | #endif // choose signal handler |
1182 | |
1183 | // ************************************************************************** // |
1184 | // ************** execution_monitor ************** // |
1185 | // ************************************************************************** // |
1186 | |
1187 | execution_monitor::execution_monitor() |
1188 | : p_catch_system_errors( true ) |
1189 | , p_auto_start_dbg( false ) |
1190 | , p_timeout( 0 ) |
1191 | , p_use_alt_stack( true ) |
1192 | , p_detect_fp_exceptions( fpe::BOOST_FPE_OFF ) |
1193 | {} |
1194 | |
1195 | //____________________________________________________________________________// |
1196 | |
1197 | int |
1198 | execution_monitor::execute( boost::function<int ()> const& F ) |
1199 | { |
1200 | if( debug::under_debugger() ) |
1201 | p_catch_system_errors.value = false; |
1202 | |
1203 | BOOST_TEST_I_TRY { |
1204 | detail::fpe_except_guard G( p_detect_fp_exceptions ); |
1205 | unit_test::ut_detail::ignore_unused_variable_warning( G ); |
1206 | |
1207 | return catch_signals( F ); |
1208 | } |
1209 | |
1210 | #ifndef BOOST_NO_EXCEPTIONS |
1211 | |
1212 | // Catch-clause reference arguments are a bit different from function |
1213 | // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't |
1214 | // required. Programmers ask for const anyhow, so we supply it. That's |
1215 | // easier than answering questions about non-const usage. |
1216 | |
1217 | catch( char const* ex ) |
1218 | { detail::report_error( ec: execution_exception::cpp_exception_error, |
1219 | format: "C string: %s" , ex ); } |
1220 | catch( std::string const& ex ) |
1221 | { detail::report_error( ec: execution_exception::cpp_exception_error, |
1222 | format: "std::string: %s" , ex.c_str() ); } |
1223 | |
1224 | // std:: exceptions |
1225 | #ifdef BOOST_NO_TYPEID |
1226 | #define CATCH_AND_REPORT_STD_EXCEPTION( ex_name ) \ |
1227 | catch( ex_name const& ex ) \ |
1228 | { detail::report_error( execution_exception::cpp_exception_error, \ |
1229 | current_exception_cast<boost::exception const>(), \ |
1230 | #ex_name ": %s", ex.what() ); } \ |
1231 | /**/ |
1232 | #else |
1233 | #define CATCH_AND_REPORT_STD_EXCEPTION( ex_name ) \ |
1234 | catch( ex_name const& ex ) \ |
1235 | { detail::report_error( execution_exception::cpp_exception_error, \ |
1236 | current_exception_cast<boost::exception const>(), \ |
1237 | "%s: %s", detail::typeid_name(ex), ex.what() ); } \ |
1238 | /**/ |
1239 | #endif |
1240 | |
1241 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc ) |
1242 | |
1243 | #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) |
1244 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) |
1245 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) |
1246 | #else |
1247 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) |
1248 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) |
1249 | #endif |
1250 | |
1251 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_exception ) |
1252 | CATCH_AND_REPORT_STD_EXCEPTION( std::domain_error ) |
1253 | CATCH_AND_REPORT_STD_EXCEPTION( std::invalid_argument ) |
1254 | CATCH_AND_REPORT_STD_EXCEPTION( std::length_error ) |
1255 | CATCH_AND_REPORT_STD_EXCEPTION( std::out_of_range ) |
1256 | CATCH_AND_REPORT_STD_EXCEPTION( std::range_error ) |
1257 | CATCH_AND_REPORT_STD_EXCEPTION( std::overflow_error ) |
1258 | CATCH_AND_REPORT_STD_EXCEPTION( std::underflow_error ) |
1259 | CATCH_AND_REPORT_STD_EXCEPTION( std::logic_error ) |
1260 | CATCH_AND_REPORT_STD_EXCEPTION( std::runtime_error ) |
1261 | CATCH_AND_REPORT_STD_EXCEPTION( std::exception ) |
1262 | #undef CATCH_AND_REPORT_STD_EXCEPTION |
1263 | |
1264 | catch( boost::exception const& ex ) |
1265 | { detail::report_error( ec: execution_exception::cpp_exception_error, |
1266 | be: &ex, |
1267 | #ifdef BOOST_NO_TYPEID |
1268 | "unknown boost::exception" ); } |
1269 | #else |
1270 | format: typeid(ex).name() ); } |
1271 | #endif |
1272 | |
1273 | // system errors |
1274 | catch( system_error const& ex ) |
1275 | { detail::report_error( ec: execution_exception::cpp_exception_error, |
1276 | format: "system_error produced by: %s: %s" , ex.p_failed_exp, std::strerror( errnum: ex.p_errno ) ); } |
1277 | catch( detail::system_signal_exception const& ex ) |
1278 | { ex.report(); } |
1279 | |
1280 | // not an error |
1281 | catch( execution_aborted const& ) |
1282 | { return 0; } |
1283 | |
1284 | // just forward |
1285 | catch( execution_exception const& ) |
1286 | { throw; } |
1287 | |
1288 | // unknown error |
1289 | catch( ... ) |
1290 | { detail::report_error( ec: execution_exception::cpp_exception_error, format: "unknown type" ); } |
1291 | |
1292 | #endif // !BOOST_NO_EXCEPTION |
1293 | |
1294 | return 0; // never reached; supplied to quiet compiler warnings |
1295 | } // execute |
1296 | |
1297 | //____________________________________________________________________________// |
1298 | |
1299 | namespace detail { |
1300 | |
1301 | struct forward { |
1302 | explicit forward( boost::function<void ()> const& F ) : m_F( F ) {} |
1303 | |
1304 | int operator()() { m_F(); return 0; } |
1305 | |
1306 | boost::function<void ()> const& m_F; |
1307 | }; |
1308 | |
1309 | } // namespace detail |
1310 | void |
1311 | execution_monitor::vexecute( boost::function<void ()> const& F ) |
1312 | { |
1313 | execute( F: detail::forward( F ) ); |
1314 | } |
1315 | |
1316 | // ************************************************************************** // |
1317 | // ************** system_error ************** // |
1318 | // ************************************************************************** // |
1319 | |
1320 | system_error::system_error( char const* exp ) |
1321 | #ifdef UNDER_CE |
1322 | : p_errno( GetLastError() ) |
1323 | #else |
1324 | : p_errno( errno ) |
1325 | #endif |
1326 | , p_failed_exp( exp ) |
1327 | {} |
1328 | |
1329 | //____________________________________________________________________________// |
1330 | |
1331 | // ************************************************************************** // |
1332 | // ************** execution_exception ************** // |
1333 | // ************************************************************************** // |
1334 | |
1335 | execution_exception::execution_exception( error_code ec_, const_string what_msg_, location const& location_ ) |
1336 | : m_error_code( ec_ ) |
1337 | , m_what( what_msg_.empty() ? BOOST_TEST_L( "uncaught exception, system error or abort requested" ) : what_msg_ ) |
1338 | , m_location( location_ ) |
1339 | {} |
1340 | |
1341 | //____________________________________________________________________________// |
1342 | |
1343 | execution_exception::location::location( char const* file_name, size_t line_num, char const* func ) |
1344 | : m_file_name( file_name ? file_name : "unknown location" ) |
1345 | , m_line_num( line_num ) |
1346 | , m_function( func ) |
1347 | {} |
1348 | |
1349 | //____________________________________________________________________________// |
1350 | |
1351 | // ************************************************************************** // |
1352 | // **************Floating point exception management interface ************** // |
1353 | // ************************************************************************** // |
1354 | |
1355 | namespace fpe { |
1356 | |
1357 | unsigned |
1358 | enable( unsigned mask ) |
1359 | { |
1360 | boost::ignore_unused(mask); |
1361 | |
1362 | #if defined(UNDER_CE) |
1363 | /* Not Implemented in Windows CE */ |
1364 | return 0; |
1365 | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) |
1366 | _clearfp(); |
1367 | |
1368 | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) |
1369 | unsigned old_cw = ::_controlfp( 0, 0 ); |
1370 | ::_controlfp( old_cw & ~mask, BOOST_FPE_ALL ); |
1371 | #else |
1372 | unsigned old_cw; |
1373 | if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) |
1374 | return BOOST_FPE_INV; |
1375 | |
1376 | // Set the control word |
1377 | if( ::_controlfp_s( 0, old_cw & ~mask, BOOST_FPE_ALL ) != 0 ) |
1378 | return BOOST_FPE_INV; |
1379 | #endif |
1380 | |
1381 | return ~old_cw & BOOST_FPE_ALL; |
1382 | #elif defined(__GLIBC__) && defined(__USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) |
1383 | ::feclearexcept(BOOST_FPE_ALL); |
1384 | int res = ::feenableexcept( mask ); |
1385 | return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; |
1386 | #else |
1387 | /* Not Implemented */ |
1388 | return 0; |
1389 | #endif |
1390 | } |
1391 | |
1392 | //____________________________________________________________________________// |
1393 | |
1394 | unsigned |
1395 | disable( unsigned mask ) |
1396 | { |
1397 | boost::ignore_unused(mask); |
1398 | |
1399 | #if defined(UNDER_CE) |
1400 | /* Not Implemented in Windows CE */ |
1401 | return 0; |
1402 | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) |
1403 | _clearfp(); |
1404 | |
1405 | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) |
1406 | unsigned old_cw = ::_controlfp( 0, 0 ); |
1407 | ::_controlfp( old_cw | mask, BOOST_FPE_ALL ); |
1408 | #else |
1409 | unsigned old_cw; |
1410 | if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) |
1411 | return BOOST_FPE_INV; |
1412 | |
1413 | // Set the control word |
1414 | if( ::_controlfp_s( 0, old_cw | mask, BOOST_FPE_ALL ) != 0 ) |
1415 | return BOOST_FPE_INV; |
1416 | #endif |
1417 | |
1418 | return ~old_cw & BOOST_FPE_ALL; |
1419 | #elif defined(__GLIBC__) && defined(__USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) |
1420 | ::feclearexcept(BOOST_FPE_ALL); |
1421 | int res = ::fedisableexcept( mask ); |
1422 | return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; |
1423 | #else |
1424 | /* Not Implemented */ |
1425 | return BOOST_FPE_INV; |
1426 | #endif |
1427 | } |
1428 | |
1429 | //____________________________________________________________________________// |
1430 | |
1431 | } // namespace fpe |
1432 | |
1433 | } // namespace boost |
1434 | |
1435 | #include <boost/test/detail/enable_warnings.hpp> |
1436 | |
1437 | #endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER |
1438 | |
1439 | |