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