]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | // | |
b32b8144 FG |
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. | |
7c673cae FG |
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> | |
7c673cae FG |
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 | |
b32b8144 | 34 | #ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
35 | #include <boost/exception/get_error_info.hpp> // for get_error_info |
36 | #include <boost/exception/current_exception_cast.hpp> // for current_exception_cast | |
92f5a8d4 | 37 | #include <boost/exception/diagnostic_information.hpp> |
7c673cae FG |
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 | |
92f5a8d4 | 50 | #include <stdio.h> |
7c673cae | 51 | #include <cstdarg> // for varargs |
92f5a8d4 TL |
52 | #include <stdarg.h> |
53 | #include <cmath> // for ceil | |
7c673cae FG |
54 | |
55 | #include <iostream> // for varargs | |
56 | ||
57 | #ifdef BOOST_NO_STDC_NAMESPACE | |
92f5a8d4 | 58 | namespace std { using ::strerror; using ::strlen; using ::strncat; using ::ceil; } |
7c673cae FG |
59 | #endif |
60 | ||
61 | // to use vsnprintf | |
92f5a8d4 | 62 | #if defined(__SUNPRO_CC) || defined(__SunOS) || defined(__QNXNTO__) || defined(__VXWORKS__) |
7c673cae FG |
63 | using std::va_list; |
64 | #endif | |
65 | ||
11fdf7f2 TL |
66 | #if defined(__VXWORKS__) |
67 | # define BOOST_TEST_LIMITED_SIGNAL_DETAILS | |
68 | #endif | |
69 | ||
7c673cae | 70 | #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING |
92f5a8d4 TL |
71 | |
72 | # if !defined(_WIN32_WINNT) // WinXP | |
73 | # define _WIN32_WINNT 0x0501 | |
74 | # endif | |
75 | ||
7c673cae FG |
76 | # include <windows.h> |
77 | ||
78 | # if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) | |
79 | # include <eh.h> | |
80 | # endif | |
81 | ||
20effc67 | 82 | # if defined(BOOST_BORLANDC) && BOOST_BORLANDC >= 0x560 || defined(__MWERKS__) |
7c673cae FG |
83 | # include <stdint.h> |
84 | # endif | |
85 | ||
20effc67 | 86 | # if defined(BOOST_BORLANDC) && BOOST_BORLANDC < 0x560 |
7c673cae FG |
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 | ||
92f5a8d4 TL |
109 | # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) /* WinXP */ |
110 | # define BOOST_TEST_WIN32_WAITABLE_TIMERS | |
111 | # endif | |
112 | ||
7c673cae FG |
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 | ||
20effc67 | 126 | # if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE) |
7c673cae FG |
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 | ||
b32b8144 | 207 | #ifdef BOOST_NO_EXCEPTIONS |
7c673cae FG |
208 | void throw_exception( std::exception const & e ) { abort(); } |
209 | #endif | |
210 | ||
211 | // ************************************************************************** // | |
212 | // ************** report_error ************** // | |
213 | // ************************************************************************** // | |
214 | ||
215 | namespace detail { | |
216 | ||
20effc67 | 217 | #ifdef BOOST_BORLANDC |
7c673cae FG |
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)) || \ | |
92f5a8d4 TL |
221 | defined(UNDER_CE) || \ |
222 | (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) | |
7c673cae FG |
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 | ||
20effc67 TL |
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 | ||
b32b8144 | 236 | #ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
237 | |
238 | template <typename ErrorInfo> | |
239 | typename ErrorInfo::value_type | |
240 | extract( 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 | |
20effc67 | 253 | BOOST_TEST_PRINTF_ATTRIBUTE_CHECK(3, 0) |
7c673cae FG |
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 | |
20effc67 | 272 | BOOST_TEST_PRINTF_ATTRIBUTE_CHECK(3, 4) |
7c673cae FG |
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 ); | |
279 | } | |
280 | ||
281 | #endif | |
282 | ||
283 | //____________________________________________________________________________// | |
284 | ||
285 | static void | |
20effc67 | 286 | BOOST_TEST_PRINTF_ATTRIBUTE_CHECK(2, 3) |
7c673cae FG |
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, 0, format, &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 | |
b32b8144 FG |
311 | m_previously_enabled = fpe::disable( fpe::BOOST_FPE_ALL ); |
312 | if( m_previously_enabled != fpe::BOOST_FPE_INV && detect_fpe != fpe::BOOST_FPE_OFF ) | |
7c673cae FG |
313 | fpe::enable( detect_fpe ); |
314 | } | |
315 | ~fpe_except_guard() | |
316 | { | |
317 | if( m_detect_fpe != fpe::BOOST_FPE_OFF ) | |
318 | fpe::disable( m_detect_fpe ); | |
b32b8144 FG |
319 | if( m_previously_enabled != fpe::BOOST_FPE_INV ) |
320 | fpe::enable( m_previously_enabled ); | |
7c673cae FG |
321 | } |
322 | ||
323 | unsigned m_detect_fpe; | |
b32b8144 | 324 | unsigned m_previously_enabled; |
7c673cae FG |
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(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 ) { | |
11fdf7f2 | 386 | #ifdef __VXWORKS__ |
92f5a8d4 | 387 | // a bit of a hack to adapt code to small m_sig_info VxWorks uses |
11fdf7f2 TL |
388 | #define si_addr si_value.sival_int |
389 | #define si_band si_value.sival_int | |
92f5a8d4 | 390 | #else |
7c673cae FG |
391 | case SI_USER: |
392 | report_error( execution_exception::system_error, | |
393 | "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; | |
92f5a8d4 | 396 | #endif |
7c673cae FG |
397 | case SI_QUEUE: |
398 | report_error( execution_exception::system_error, | |
399 | "signal: sent by sigqueue()" ); | |
400 | break; | |
401 | case SI_TIMER: | |
402 | report_error( execution_exception::system_error, | |
403 | "signal: the expiration of a timer set by timer_settimer()" ); | |
404 | break; | |
92f5a8d4 TL |
405 | // OpenBSD was missing SI_ASYNCIO and SI_MESGQ |
406 | #ifdef SI_ASYNCIO | |
7c673cae FG |
407 | case SI_ASYNCIO: |
408 | report_error( execution_exception::system_error, | |
409 | "signal: generated by the completion of an asynchronous I/O request" ); | |
410 | break; | |
92f5a8d4 TL |
411 | #endif |
412 | #ifdef SI_MESGQ | |
7c673cae FG |
413 | case SI_MESGQ: |
414 | report_error( execution_exception::system_error, | |
415 | "signal: generated by the the arrival of a message on an empty message queue" ); | |
416 | break; | |
92f5a8d4 | 417 | #endif |
7c673cae FG |
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( execution_exception::system_fatal_error, | |
428 | "signal: illegal opcode; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 429 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
430 | break; |
431 | case ILL_ILLTRP: | |
432 | report_error( execution_exception::system_fatal_error, | |
433 | "signal: illegal trap; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 434 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
435 | break; |
436 | case ILL_PRVREG: | |
437 | report_error( execution_exception::system_fatal_error, | |
438 | "signal: privileged register; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 439 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
440 | break; |
441 | case ILL_BADSTK: | |
442 | report_error( execution_exception::system_fatal_error, | |
443 | "signal: internal stack error; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 444 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
445 | break; |
446 | #endif | |
447 | case ILL_ILLOPN: | |
448 | report_error( execution_exception::system_fatal_error, | |
449 | "signal: illegal operand; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 450 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
451 | break; |
452 | case ILL_ILLADR: | |
453 | report_error( execution_exception::system_fatal_error, | |
454 | "signal: illegal addressing mode; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 455 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
456 | break; |
457 | case ILL_PRVOPC: | |
458 | report_error( execution_exception::system_fatal_error, | |
459 | "signal: privileged opcode; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 460 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
461 | break; |
462 | case ILL_COPROC: | |
463 | report_error( execution_exception::system_fatal_error, | |
464 | "signal: co-processor error; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 465 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
466 | break; |
467 | default: | |
468 | report_error( execution_exception::system_fatal_error, | |
469 | "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)", | |
92f5a8d4 | 470 | m_sig_info->si_code, (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
471 | break; |
472 | } | |
473 | break; | |
474 | ||
475 | case SIGFPE: | |
476 | switch( m_sig_info->si_code ) { | |
477 | case FPE_INTDIV: | |
478 | report_error( execution_exception::system_error, | |
479 | "signal: integer divide by zero; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 480 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
481 | break; |
482 | case FPE_INTOVF: | |
483 | report_error( execution_exception::system_error, | |
484 | "signal: integer overflow; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 485 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
486 | break; |
487 | case FPE_FLTDIV: | |
488 | report_error( execution_exception::system_error, | |
489 | "signal: floating point divide by zero; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 490 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
491 | break; |
492 | case FPE_FLTOVF: | |
493 | report_error( execution_exception::system_error, | |
494 | "signal: floating point overflow; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 495 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
496 | break; |
497 | case FPE_FLTUND: | |
498 | report_error( execution_exception::system_error, | |
499 | "signal: floating point underflow; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 500 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
501 | break; |
502 | case FPE_FLTRES: | |
503 | report_error( execution_exception::system_error, | |
504 | "signal: floating point inexact result; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 505 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
506 | break; |
507 | case FPE_FLTINV: | |
508 | report_error( execution_exception::system_error, | |
509 | "signal: invalid floating point operation; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 510 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
511 | break; |
512 | case FPE_FLTSUB: | |
513 | report_error( execution_exception::system_error, | |
514 | "signal: subscript out of range; address of failing instruction: 0x%08lx", | |
92f5a8d4 | 515 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
516 | break; |
517 | default: | |
518 | report_error( execution_exception::system_error, | |
519 | "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)", | |
92f5a8d4 | 520 | m_sig_info->si_code, (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
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( execution_exception::system_fatal_error, | |
530 | "memory access violation at address: 0x%08lx: no mapping at fault address", | |
92f5a8d4 | 531 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
532 | break; |
533 | case SEGV_ACCERR: | |
534 | report_error( execution_exception::system_fatal_error, | |
535 | "memory access violation at address: 0x%08lx: invalid permissions", | |
92f5a8d4 | 536 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
537 | break; |
538 | #endif | |
539 | default: | |
540 | report_error( execution_exception::system_fatal_error, | |
541 | "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", | |
92f5a8d4 | 542 | m_sig_info->si_code, (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
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( execution_exception::system_fatal_error, | |
552 | "memory access violation at address: 0x%08lx: invalid address alignment", | |
92f5a8d4 | 553 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
554 | break; |
555 | case BUS_ADRERR: | |
556 | report_error( execution_exception::system_fatal_error, | |
557 | "memory access violation at address: 0x%08lx: non-existent physical address", | |
92f5a8d4 | 558 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
559 | break; |
560 | case BUS_OBJERR: | |
561 | report_error( execution_exception::system_fatal_error, | |
562 | "memory access violation at address: 0x%08lx: object specific hardware error", | |
92f5a8d4 | 563 | (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
564 | break; |
565 | #endif | |
566 | default: | |
567 | report_error( execution_exception::system_fatal_error, | |
568 | "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", | |
92f5a8d4 | 569 | m_sig_info->si_code, (uintptr_t) m_sig_info->si_addr ); |
7c673cae FG |
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( execution_exception::system_error, | |
581 | "data input available; band event %d", | |
582 | (int)m_sig_info->si_band ); | |
583 | break; | |
584 | case POLL_OUT: | |
585 | report_error( execution_exception::system_error, | |
586 | "output buffers available; band event %d", | |
587 | (int)m_sig_info->si_band ); | |
588 | break; | |
589 | case POLL_MSG: | |
590 | report_error( execution_exception::system_error, | |
591 | "input message available; band event %d", | |
592 | (int)m_sig_info->si_band ); | |
593 | break; | |
594 | case POLL_ERR: | |
595 | report_error( execution_exception::system_error, | |
596 | "i/o error; band event %d", | |
597 | (int)m_sig_info->si_band ); | |
598 | break; | |
599 | case POLL_PRI: | |
600 | report_error( execution_exception::system_error, | |
601 | "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( execution_exception::system_error, | |
614 | "signal: SIGPOLL, si_code: %d (asynchronous I/O event occurred; band event %d)", | |
92f5a8d4 | 615 | m_sig_info->si_code, (int)m_sig_info->si_band ); |
7c673cae FG |
616 | break; |
617 | } | |
618 | break; | |
619 | ||
620 | #endif | |
621 | ||
622 | case SIGABRT: | |
623 | report_error( execution_exception::system_error, | |
624 | "signal: SIGABRT (application abort requested)" ); | |
625 | break; | |
626 | ||
627 | case SIGALRM: | |
628 | report_error( execution_exception::timeout_error, | |
629 | "signal: SIGALRM (timeout while executing function)" ); | |
630 | break; | |
631 | ||
632 | default: | |
633 | report_error( execution_exception::system_error, | |
634 | "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( &m_new_action, 0, 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( m_sig, &m_old_action , sigaction_ptr() ); | |
709 | } | |
710 | ||
711 | //____________________________________________________________________________// | |
712 | ||
713 | // ************************************************************************** // | |
714 | // ************** boost::detail::signal_handler ************** // | |
715 | // ************************************************************************** // | |
716 | ||
717 | class signal_handler { | |
718 | public: | |
719 | // Constructor | |
f67539c2 TL |
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 ); | |
7c673cae FG |
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; | |
f67539c2 | 747 | unsigned long int m_timeout_microseconds; |
7c673cae FG |
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 | ||
f67539c2 TL |
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 ) | |
7c673cae | 776 | : m_prev_handler( s_active_handler ) |
92f5a8d4 TL |
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 ) | |
7c673cae | 782 | #ifdef BOOST_TEST_CATCH_SIGPOLL |
92f5a8d4 | 783 | , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) |
7c673cae | 784 | #endif |
92f5a8d4 TL |
785 | , m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack ) |
786 | , m_ALRM_action( SIGALRM, timeout_microseconds > 0, attach_dbg, alt_stack ) | |
7c673cae FG |
787 | { |
788 | s_active_handler = this; | |
789 | ||
92f5a8d4 | 790 | if( m_timeout_microseconds > 0 ) { |
7c673cae | 791 | ::alarm( 0 ); |
92f5a8d4 | 792 | ::alarm( static_cast<unsigned int>(std::ceil(timeout_microseconds / 1E6) )); // alarm has a precision to the seconds |
7c673cae FG |
793 | } |
794 | ||
795 | #ifdef BOOST_TEST_USE_ALT_STACK | |
796 | if( alt_stack ) { | |
797 | stack_t sigstk; | |
798 | std::memset( &sigstk, 0, 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 | ||
92f5a8d4 | 818 | if( m_timeout_microseconds > 0 ) |
7c673cae FG |
819 | ::alarm( 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 = { 0, 0, 0 }; | |
827 | #else | |
828 | stack_t sigstk = { }; | |
829 | #endif | |
830 | ||
831 | sigstk.ss_size = MINSIGSTKSZ; | |
832 | sigstk.ss_flags = SS_DISABLE; | |
833 | if( ::sigaltstack( &sigstk, 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( 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( signal_handler::jump_buffer(), 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( 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( 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( 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 | ||
20effc67 | 916 | #if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0564)) |
7c673cae FG |
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 ) | |
92f5a8d4 | 934 | , m_timeout( false ) |
7c673cae FG |
935 | {} |
936 | ||
92f5a8d4 | 937 | void set_timed_out(); |
7c673cae FG |
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; | |
92f5a8d4 | 948 | bool m_timeout; |
7c673cae FG |
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 | ||
92f5a8d4 TL |
963 | void |
964 | system_signal_exception::set_timed_out() | |
965 | { | |
966 | m_timeout = true; | |
967 | } | |
968 | ||
969 | //____________________________________________________________________________// | |
970 | ||
7c673cae FG |
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: | |
92f5a8d4 TL |
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 | } | |
7c673cae FG |
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 | ||
92f5a8d4 TL |
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 | ||
7c673cae FG |
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 | } | |
92f5a8d4 TL |
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 | ||
7c673cae FG |
1235 | } |
1236 | __finally { | |
92f5a8d4 TL |
1237 | |
1238 | #if defined(BOOST_TEST_WIN32_WAITABLE_TIMERS) | |
1239 | if( htimer != INVALID_HANDLE_VALUE ) { | |
1240 | ::CloseHandle(htimer); | |
1241 | } | |
1242 | #endif | |
1243 | ||
7c673cae FG |
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 ); | |
92f5a8d4 | 1299 | boost::ignore_unused( G ); |
7c673cae FG |
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( execution_exception::cpp_exception_error, | |
1313 | "C string: %s", ex ); } | |
1314 | catch( std::string const& ex ) | |
1315 | { detail::report_error( execution_exception::cpp_exception_error, | |
1316 | "std::string: %s", ex.c_str() ); } | |
1317 | ||
92f5a8d4 TL |
1318 | // boost::exception (before std::exception, with extended diagnostic) |
1319 | catch( boost::exception const& ex ) | |
1320 | { detail::report_error( execution_exception::cpp_exception_error, | |
1321 | &ex, | |
1322 | "%s", boost::diagnostic_information(ex).c_str() ); } | |
1323 | ||
7c673cae FG |
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 ) | |
7c673cae FG |
1342 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) |
1343 | CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) | |
7c673cae FG |
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 | ||
7c673cae FG |
1357 | // system errors |
1358 | catch( system_error const& ex ) | |
1359 | { detail::report_error( execution_exception::cpp_exception_error, | |
1360 | "system_error produced by: %s: %s", ex.p_failed_exp, std::strerror( 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( execution_exception::cpp_exception_error, "unknown type" ); } | |
1375 | ||
b32b8144 | 1376 | #endif // !BOOST_NO_EXCEPTIONS |
7c673cae | 1377 | |
f67539c2 | 1378 | BOOST_TEST_UNREACHABLE_RETURN(0); // never reached; supplied to quiet compiler warnings |
7c673cae FG |
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( 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 | ||
b32b8144 FG |
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 | ||
7c673cae FG |
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); | |
b32b8144 | 1451 | #if defined(BOOST_TEST_FPE_SUPPORT_WITH_SEH__) |
7c673cae FG |
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 | |
7c673cae | 1466 | return ~old_cw & BOOST_FPE_ALL; |
b32b8144 FG |
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; | |
7c673cae FG |
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 */ | |
b32b8144 | 1478 | return BOOST_FPE_OFF; |
7c673cae FG |
1479 | #endif |
1480 | } | |
1481 | ||
1482 | //____________________________________________________________________________// | |
1483 | ||
1484 | unsigned | |
1485 | disable( unsigned mask ) | |
1486 | { | |
1487 | boost::ignore_unused(mask); | |
1488 | ||
b32b8144 | 1489 | #if defined(BOOST_TEST_FPE_SUPPORT_WITH_SEH__) |
7c673cae | 1490 | _clearfp(); |
7c673cae FG |
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 | |
7c673cae | 1503 | return ~old_cw & BOOST_FPE_ALL; |
b32b8144 FG |
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; | |
7c673cae FG |
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 |