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