1440 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			1440 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //  (C) Copyright Gennadiy Rozental 2001. | ||
|  | //  (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001. | ||
|  | //  Use, modification, and distribution are subject to the | ||
|  | //  Boost Software License, Version 1.0. (See accompanying file | ||
|  | //  http://www.boost.org/LICENSE_1_0.txt) | ||
|  | 
 | ||
|  | //  See http://www.boost.org/libs/test for the library home page. | ||
|  | // | ||
|  | ///  @file | ||
|  | ///  Provides execution monitor implementation for all supported | ||
|  | ///  configurations, including Microsoft structured exception based, unix signals | ||
|  | ///  based and special workarounds for borland | ||
|  | /// | ||
|  | ///  Note that when testing requirements or user wishes preclude use of this | ||
|  | ///  file as a separate compilation unit, it may be included as a header file. | ||
|  | /// | ||
|  | ///  Header dependencies are deliberately restricted to reduce coupling to other | ||
|  | ///  boost libraries. | ||
|  | // *************************************************************************** | ||
|  | 
 | ||
|  | #ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER | ||
|  | #define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER | ||
|  | 
 | ||
|  | // Boost.Test | ||
|  | #include <boost/test/detail/config.hpp> | ||
|  | #include <boost/test/detail/workaround.hpp> | ||
|  | #include <boost/test/detail/throw_exception.hpp> | ||
|  | #include <boost/test/execution_monitor.hpp> | ||
|  | #include <boost/test/debug.hpp> | ||
|  | 
 | ||
|  | // Boost | ||
|  | #include <boost/cstdlib.hpp>    // for exit codes | ||
|  | #include <boost/config.hpp>     // for workarounds | ||
|  | #include <boost/core/ignore_unused.hpp> // for ignore_unused | ||
|  | #ifndef BOOST_NO_EXCEPTION | ||
|  | #include <boost/exception/get_error_info.hpp> // for get_error_info | ||
|  | #include <boost/exception/current_exception_cast.hpp> // for current_exception_cast | ||
|  | #endif | ||
|  | 
 | ||
|  | // STL | ||
|  | #include <string>               // for std::string | ||
|  | #include <new>                  // for std::bad_alloc | ||
|  | #include <typeinfo>             // for std::bad_cast, std::bad_typeid | ||
|  | #include <exception>            // for std::exception, std::bad_exception | ||
|  | #include <stdexcept>            // for std exception hierarchy | ||
|  | #include <cstring>              // for C string API | ||
|  | #include <cassert>              // for assert | ||
|  | #include <cstddef>              // for NULL | ||
|  | #include <cstdio>               // for vsnprintf | ||
|  | #include <cstdarg>              // for varargs | ||
|  | 
 | ||
|  | #include <iostream>              // for varargs | ||
|  | 
 | ||
|  | #ifdef BOOST_NO_STDC_NAMESPACE | ||
|  | namespace std { using ::strerror; using ::strlen; using ::strncat; } | ||
|  | #endif | ||
|  | 
 | ||
|  | // to use vsnprintf | ||
|  | #if defined(__SUNPRO_CC) || defined(__SunOS) | ||
|  | #  include <stdio.h> | ||
|  | #  include <stdarg.h> | ||
|  | using std::va_list; | ||
|  | #endif | ||
|  | 
 | ||
|  | // to use vsnprintf | ||
|  | #if defined(__QNXNTO__) | ||
|  | #  include <stdio.h> | ||
|  | using std::va_list; | ||
|  | #endif | ||
|  | 
 | ||
|  | #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING | ||
|  | #  include <windows.h> | ||
|  | 
 | ||
|  | #  if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) | ||
|  | #    include <eh.h> | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 || defined(__MWERKS__) | ||
|  | #    include <stdint.h> | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if defined(__BORLANDC__) && __BORLANDC__ < 0x560 | ||
|  |     typedef unsigned uintptr_t; | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if defined(UNDER_CE) && BOOST_WORKAROUND(_MSC_VER,  < 1500 ) | ||
|  |    typedef void* uintptr_t; | ||
|  | #  elif defined(UNDER_CE) | ||
|  | #  include <crtdefs.h> | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE) | ||
|  | #    include <crtdbg.h> | ||
|  | #    define BOOST_TEST_CRT_HOOK_TYPE    _CRT_REPORT_HOOK | ||
|  | #    define BOOST_TEST_CRT_ASSERT       _CRT_ASSERT | ||
|  | #    define BOOST_TEST_CRT_ERROR        _CRT_ERROR | ||
|  | #    define BOOST_TEST_CRT_SET_HOOK(H)  _CrtSetReportHook(H) | ||
|  | #  else | ||
|  | #    define BOOST_TEST_CRT_HOOK_TYPE    void* | ||
|  | #    define BOOST_TEST_CRT_ASSERT       2 | ||
|  | #    define BOOST_TEST_CRT_ERROR        1 | ||
|  | #    define BOOST_TEST_CRT_SET_HOOK(H)  (void*)(H) | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if (!BOOST_WORKAROUND(_MSC_VER,  >= 1400 ) && \ | ||
|  |       !defined(BOOST_COMO)) || defined(UNDER_CE) | ||
|  | 
 | ||
|  | typedef void* _invalid_parameter_handler; | ||
|  | 
 | ||
|  | inline _invalid_parameter_handler | ||
|  | _set_invalid_parameter_handler( _invalid_parameter_handler arg ) | ||
|  | { | ||
|  |     return arg; | ||
|  | } | ||
|  | 
 | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE) | ||
|  | 
 | ||
|  | namespace { void _set_se_translator( void* ) {} } | ||
|  | 
 | ||
|  | #  endif | ||
|  | 
 | ||
|  | #elif defined(BOOST_HAS_SIGACTION) | ||
|  | 
 | ||
|  | #  define BOOST_SIGACTION_BASED_SIGNAL_HANDLING | ||
|  | 
 | ||
|  | #  include <unistd.h> | ||
|  | #  include <signal.h> | ||
|  | #  include <setjmp.h> | ||
|  | 
 | ||
|  | #  if defined(__FreeBSD__) | ||
|  | 
 | ||
|  | #    include <osreldate.h> | ||
|  | 
 | ||
|  | #    ifndef SIGPOLL | ||
|  | #      define SIGPOLL SIGIO | ||
|  | #    endif | ||
|  | 
 | ||
|  | #    if (__FreeBSD_version < 70100) | ||
|  | 
 | ||
|  | #      define ILL_ILLADR 0 // ILL_RESAD_FAULT | ||
|  | #      define ILL_PRVOPC ILL_PRIVIN_FAULT | ||
|  | #      define ILL_ILLOPN 2 // ILL_RESOP_FAULT | ||
|  | #      define ILL_COPROC ILL_FPOP_FAULT | ||
|  | 
 | ||
|  | #      define BOOST_TEST_LIMITED_SIGNAL_DETAILS | ||
|  | 
 | ||
|  | #    endif | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if defined(__ANDROID__) | ||
|  | #    include <android/api-level.h> | ||
|  | #  endif | ||
|  | 
 | ||
|  | // documentation of BOOST_TEST_DISABLE_ALT_STACK in execution_monitor.hpp | ||
|  | #  if !defined(__CYGWIN__) && !defined(__QNXNTO__) && !defined(__bgq__) && \ | ||
|  |    (!defined(__ANDROID__) || __ANDROID_API__ >= 8) && \ | ||
|  |    !defined(BOOST_TEST_DISABLE_ALT_STACK) | ||
|  | #    define BOOST_TEST_USE_ALT_STACK | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  if defined(SIGPOLL) && !defined(__CYGWIN__)                              && \ | ||
|  |       !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))  && \ | ||
|  |       !defined(__NetBSD__)                                                  && \ | ||
|  |       !defined(__QNXNTO__) | ||
|  | #    define BOOST_TEST_CATCH_SIGPOLL | ||
|  | #  endif | ||
|  | 
 | ||
|  | #  ifdef BOOST_TEST_USE_ALT_STACK | ||
|  | #    define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ | ||
|  | #  endif | ||
|  | 
 | ||
|  | 
 | ||
|  | #else | ||
|  | 
 | ||
|  | #  define BOOST_NO_SIGNAL_HANDLING | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  | #ifndef UNDER_CE | ||
|  | #include <errno.h> | ||
|  | #endif | ||
|  | 
 | ||
|  | #if !defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI) | ||
|  | #  include <boost/core/demangle.hpp> | ||
|  | #endif | ||
|  | 
 | ||
|  | #include <boost/test/detail/suppress_warnings.hpp> | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                 throw_exception              ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | #ifdef BOOST_NO_EXCEPTION | ||
|  | void throw_exception( std::exception const & e ) { abort(); } | ||
|  | #endif | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                  report_error                ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | #ifdef __BORLANDC__ | ||
|  | #  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) ) | ||
|  | #elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \ | ||
|  |       BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \ | ||
|  |       defined(UNDER_CE) | ||
|  | #  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) ) | ||
|  | #else | ||
|  | #  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) ) | ||
|  | #endif | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_EXCEPTION | ||
|  | 
 | ||
|  | template <typename ErrorInfo> | ||
|  | typename ErrorInfo::value_type | ||
|  | extract( boost::exception const* ex ) | ||
|  | { | ||
|  |     if( !ex ) | ||
|  |         return 0; | ||
|  | 
 | ||
|  |     typename ErrorInfo::value_type const * val = boost::get_error_info<ErrorInfo>( *ex ); | ||
|  | 
 | ||
|  |     return val ? *val : 0; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | static void | ||
|  | report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, va_list* args ) | ||
|  | { | ||
|  |     static const int REPORT_ERROR_BUFFER_SIZE = 4096; | ||
|  |     static char buf[REPORT_ERROR_BUFFER_SIZE]; | ||
|  | 
 | ||
|  |     BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); | ||
|  |     buf[sizeof(buf)-1] = 0; | ||
|  | 
 | ||
|  |     va_end( *args ); | ||
|  | 
 | ||
|  |     BOOST_TEST_I_THROW(execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ), | ||
|  |                                                                                     (size_t)extract<throw_line>( be ), | ||
|  |                                                                                     extract<throw_function>( be ) ) )); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | static void | ||
|  | report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) | ||
|  | { | ||
|  |     va_list args; | ||
|  |     va_start( args, format ); | ||
|  | 
 | ||
|  |     report_error( ec, be, format, &args ); | ||
|  | } | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | static void | ||
|  | report_error( execution_exception::error_code ec, char const* format, ... ) | ||
|  | { | ||
|  |     va_list args; | ||
|  |     va_start( args, format ); | ||
|  | 
 | ||
|  |     report_error( ec, 0, format, &args ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | template<typename Tr,typename Functor> | ||
|  | inline int | ||
|  | do_invoke( Tr const& tr, Functor const& F ) | ||
|  | { | ||
|  |     return tr ? (*tr)( F ) : F(); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | struct fpe_except_guard { | ||
|  |     explicit fpe_except_guard( unsigned detect_fpe ) | ||
|  |     : m_detect_fpe( detect_fpe ) | ||
|  |     { | ||
|  |         // prepare fp exceptions control | ||
|  |         m_previously_enabled = fpe::disable( fpe::BOOST_FPE_ALL ); | ||
|  |         if( m_previously_enabled != fpe::BOOST_FPE_INV && detect_fpe != fpe::BOOST_FPE_OFF ) | ||
|  |             fpe::enable( detect_fpe ); | ||
|  |     } | ||
|  |     ~fpe_except_guard() | ||
|  |     { | ||
|  |         if( m_detect_fpe != fpe::BOOST_FPE_OFF ) | ||
|  |             fpe::disable( m_detect_fpe ); | ||
|  |         if( m_previously_enabled != fpe::BOOST_FPE_INV ) | ||
|  |             fpe::enable( m_previously_enabled ); | ||
|  |     } | ||
|  | 
 | ||
|  |     unsigned m_detect_fpe; | ||
|  |     unsigned m_previously_enabled; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                  typeid_name                 ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | #if !defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI) | ||
|  | template<typename T> | ||
|  | std::string | ||
|  | typeid_name( T const& t ) | ||
|  | { | ||
|  |     return boost::core::demangle(typeid(t).name()); | ||
|  | } | ||
|  | #endif | ||
|  | 
 | ||
|  | } // namespace detail | ||
|  | 
 | ||
|  | #if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************       Sigaction based signal handling        ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************    boost::detail::system_signal_exception    ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | class system_signal_exception { | ||
|  | public: | ||
|  |     // Constructor | ||
|  |     system_signal_exception() | ||
|  |     : m_sig_info( 0 ) | ||
|  |     , m_context( 0 ) | ||
|  |     {} | ||
|  | 
 | ||
|  |     // Access methods | ||
|  |     void        operator()( siginfo_t* i, void* c ) | ||
|  |     { | ||
|  |         m_sig_info  = i; | ||
|  |         m_context   = c; | ||
|  |     } | ||
|  |     void        report() const; | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     siginfo_t*  m_sig_info; // system signal detailed info | ||
|  |     void*       m_context;  // signal context | ||
|  | }; | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | void | ||
|  | system_signal_exception::report() const | ||
|  | { | ||
|  |     if( !m_sig_info ) | ||
|  |         return; // no error actually occur? | ||
|  | 
 | ||
|  |     switch( m_sig_info->si_code ) { | ||
|  |     case SI_USER: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: generated by kill() (or family); uid=%d; pid=%d", | ||
|  |                       (int)m_sig_info->si_uid, (int)m_sig_info->si_pid ); | ||
|  |         break; | ||
|  |     case SI_QUEUE: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: sent by sigqueue()" ); | ||
|  |         break; | ||
|  |     case SI_TIMER: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: the expiration of a timer set by timer_settimer()" ); | ||
|  |         break; | ||
|  |     case SI_ASYNCIO: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: generated by the completion of an asynchronous I/O request" ); | ||
|  |         break; | ||
|  |     case SI_MESGQ: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: generated by the the arrival of a message on an empty message queue" ); | ||
|  |         break; | ||
|  |     default: | ||
|  |         break; | ||
|  |     } | ||
|  | 
 | ||
|  |     switch( m_sig_info->si_signo ) { | ||
|  |     case SIGILL: | ||
|  |         switch( m_sig_info->si_code ) { | ||
|  | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS | ||
|  |         case ILL_ILLOPC: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: illegal opcode; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_ILLTRP: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: illegal trap; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_PRVREG: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: privileged register; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_BADSTK: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: internal stack error; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  | #endif | ||
|  |         case ILL_ILLOPN: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: illegal operand; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_ILLADR: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: illegal addressing mode; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_PRVOPC: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: privileged opcode; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case ILL_COPROC: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: co-processor error; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         default: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)", | ||
|  |                           m_sig_info->si_addr, m_sig_info->si_code ); | ||
|  |             break; | ||
|  |         } | ||
|  |         break; | ||
|  | 
 | ||
|  |     case SIGFPE: | ||
|  |         switch( m_sig_info->si_code ) { | ||
|  |         case FPE_INTDIV: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: integer divide by zero; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_INTOVF: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: integer overflow; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTDIV: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: floating point divide by zero; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTOVF: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: floating point overflow; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTUND: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: floating point underflow; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTRES: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: floating point inexact result; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTINV: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: invalid floating point operation; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case FPE_FLTSUB: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: subscript out of range; address of failing instruction: 0x%08lx", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         default: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)", | ||
|  |                           m_sig_info->si_addr, m_sig_info->si_code ); | ||
|  |             break; | ||
|  |         } | ||
|  |         break; | ||
|  | 
 | ||
|  |     case SIGSEGV: | ||
|  |         switch( m_sig_info->si_code ) { | ||
|  | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS | ||
|  |         case SEGV_MAPERR: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "memory access violation at address: 0x%08lx: no mapping at fault address", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case SEGV_ACCERR: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "memory access violation at address: 0x%08lx: invalid permissions", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  | #endif | ||
|  |         default: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", | ||
|  |                           m_sig_info->si_addr, m_sig_info->si_code ); | ||
|  |             break; | ||
|  |         } | ||
|  |         break; | ||
|  | 
 | ||
|  |     case SIGBUS: | ||
|  |         switch( m_sig_info->si_code ) { | ||
|  | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS | ||
|  |         case BUS_ADRALN: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "memory access violation at address: 0x%08lx: invalid address alignment", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case BUS_ADRERR: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "memory access violation at address: 0x%08lx: non-existent physical address", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  |         case BUS_OBJERR: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "memory access violation at address: 0x%08lx: object specific hardware error", | ||
|  |                           m_sig_info->si_addr ); | ||
|  |             break; | ||
|  | #endif | ||
|  |         default: | ||
|  |             report_error( execution_exception::system_fatal_error, | ||
|  |                           "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", | ||
|  |                           m_sig_info->si_addr, m_sig_info->si_code ); | ||
|  |             break; | ||
|  |         } | ||
|  |         break; | ||
|  | 
 | ||
|  | #if defined(BOOST_TEST_CATCH_SIGPOLL) | ||
|  | 
 | ||
|  |     case SIGPOLL: | ||
|  |         switch( m_sig_info->si_code ) { | ||
|  | #ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS | ||
|  |         case POLL_IN: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "data input available; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  |         case POLL_OUT: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "output buffers available; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  |         case POLL_MSG: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "input message available; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  |         case POLL_ERR: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "i/o error; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  |         case POLL_PRI: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "high priority input available; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  | #if defined(POLL_ERR) && defined(POLL_HUP) && (POLL_ERR - POLL_HUP) | ||
|  |         case POLL_HUP: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "device disconnected; band event %d", | ||
|  |                           (int)m_sig_info->si_band ); | ||
|  |             break; | ||
|  | #endif | ||
|  | #endif | ||
|  |         default: | ||
|  |             report_error( execution_exception::system_error, | ||
|  |                           "signal: SIGPOLL, si_code: %d (asynchronous I/O event occurred; band event %d)", | ||
|  |                           (int)m_sig_info->si_band, m_sig_info->si_code ); | ||
|  |             break; | ||
|  |         } | ||
|  |         break; | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  |     case SIGABRT: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "signal: SIGABRT (application abort requested)" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case SIGALRM: | ||
|  |         report_error( execution_exception::timeout_error, | ||
|  |                       "signal: SIGALRM (timeout while executing function)" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     default: | ||
|  |         report_error( execution_exception::system_error, | ||
|  |                       "unrecognized signal %d", m_sig_info->si_signo ); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************         boost::detail::signal_action         ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | // Forward declaration | ||
|  | extern "C" { | ||
|  | static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); | ||
|  | static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); | ||
|  | } | ||
|  | 
 | ||
|  | class signal_action { | ||
|  |     typedef struct sigaction* sigaction_ptr; | ||
|  | public: | ||
|  |     //Constructor | ||
|  |     signal_action(); | ||
|  |     signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ); | ||
|  |     ~signal_action(); | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     int                 m_sig; | ||
|  |     bool                m_installed; | ||
|  |     struct sigaction    m_new_action; | ||
|  |     struct sigaction    m_old_action; | ||
|  | }; | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | signal_action::signal_action() | ||
|  | : m_installed( false ) | ||
|  | {} | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ) | ||
|  | : m_sig( sig ) | ||
|  | , m_installed( install ) | ||
|  | { | ||
|  |     if( !install ) | ||
|  |         return; | ||
|  | 
 | ||
|  |     std::memset( &m_new_action, 0, sizeof(struct sigaction) ); | ||
|  | 
 | ||
|  |     BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig , sigaction_ptr(), &m_new_action ) != -1 ); | ||
|  | 
 | ||
|  |     if( m_new_action.sa_sigaction || m_new_action.sa_handler ) { | ||
|  |         m_installed = false; | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_new_action.sa_flags     |= SA_SIGINFO; | ||
|  |     m_new_action.sa_sigaction  = attach_dbg ? &boost_execution_monitor_attaching_signal_handler | ||
|  |                                             : &boost_execution_monitor_jumping_signal_handler; | ||
|  |     BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 ); | ||
|  | 
 | ||
|  | #ifdef BOOST_TEST_USE_ALT_STACK | ||
|  |     if( alt_stack ) | ||
|  |         m_new_action.sa_flags |= SA_ONSTACK; | ||
|  | #endif | ||
|  | 
 | ||
|  |     BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig, &m_new_action, &m_old_action ) != -1 ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | signal_action::~signal_action() | ||
|  | { | ||
|  |     if( m_installed ) | ||
|  |         ::sigaction( m_sig, &m_old_action , sigaction_ptr() ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************        boost::detail::signal_handler         ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | class signal_handler { | ||
|  | public: | ||
|  |     // Constructor | ||
|  |     explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ); | ||
|  | 
 | ||
|  |     // Destructor | ||
|  |     ~signal_handler(); | ||
|  | 
 | ||
|  |     // access methods | ||
|  |     static sigjmp_buf&      jump_buffer() | ||
|  |     { | ||
|  |         assert( !!s_active_handler ); | ||
|  | 
 | ||
|  |         return s_active_handler->m_sigjmp_buf; | ||
|  |     } | ||
|  | 
 | ||
|  |     static system_signal_exception&  sys_sig() | ||
|  |     { | ||
|  |         assert( !!s_active_handler ); | ||
|  | 
 | ||
|  |         return s_active_handler->m_sys_sig; | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     signal_handler*         m_prev_handler; | ||
|  |     unsigned                m_timeout; | ||
|  | 
 | ||
|  |     // Note: We intentionality do not catch SIGCHLD. Users have to deal with it themselves | ||
|  |     signal_action           m_ILL_action; | ||
|  |     signal_action           m_FPE_action; | ||
|  |     signal_action           m_SEGV_action; | ||
|  |     signal_action           m_BUS_action; | ||
|  |     signal_action           m_CHLD_action; | ||
|  |     signal_action           m_POLL_action; | ||
|  |     signal_action           m_ABRT_action; | ||
|  |     signal_action           m_ALRM_action; | ||
|  | 
 | ||
|  |     sigjmp_buf              m_sigjmp_buf; | ||
|  |     system_signal_exception m_sys_sig; | ||
|  | 
 | ||
|  |     static signal_handler*  s_active_handler; | ||
|  | }; | ||
|  | 
 | ||
|  | // !! need to be placed in thread specific storage | ||
|  | typedef signal_handler* signal_handler_ptr; | ||
|  | signal_handler* signal_handler::s_active_handler = signal_handler_ptr(); | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ) | ||
|  | : m_prev_handler( s_active_handler ) | ||
|  | , m_timeout( timeout ) | ||
|  | , m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack ) | ||
|  | , m_FPE_action ( SIGFPE , detect_fpe         , attach_dbg, alt_stack ) | ||
|  | , m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack ) | ||
|  | , m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack ) | ||
|  | #ifdef BOOST_TEST_CATCH_SIGPOLL | ||
|  | , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) | ||
|  | #endif | ||
|  | , m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack ) | ||
|  | , m_ALRM_action( SIGALRM, timeout > 0        , attach_dbg, alt_stack ) | ||
|  | { | ||
|  |     s_active_handler = this; | ||
|  | 
 | ||
|  |     if( m_timeout > 0 ) { | ||
|  |         ::alarm( 0 ); | ||
|  |         ::alarm( timeout ); | ||
|  |     } | ||
|  | 
 | ||
|  | #ifdef BOOST_TEST_USE_ALT_STACK | ||
|  |     if( alt_stack ) { | ||
|  |         stack_t sigstk; | ||
|  |         std::memset( &sigstk, 0, sizeof(stack_t) ); | ||
|  | 
 | ||
|  |         BOOST_TEST_SYS_ASSERT( ::sigaltstack( 0, &sigstk ) != -1 ); | ||
|  | 
 | ||
|  |         if( sigstk.ss_flags & SS_DISABLE ) { | ||
|  |             sigstk.ss_sp    = alt_stack; | ||
|  |             sigstk.ss_size  = BOOST_TEST_ALT_STACK_SIZE; | ||
|  |             sigstk.ss_flags = 0; | ||
|  |             BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); | ||
|  |         } | ||
|  |     } | ||
|  | #endif | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | signal_handler::~signal_handler() | ||
|  | { | ||
|  |     assert( s_active_handler == this ); | ||
|  | 
 | ||
|  |     if( m_timeout > 0 ) | ||
|  |         ::alarm( 0 ); | ||
|  | 
 | ||
|  | #ifdef BOOST_TEST_USE_ALT_STACK | ||
|  | #ifdef __GNUC__ | ||
|  |     // We shouldn't need to explicitly initialize all the members here, | ||
|  |     // but gcc warns if we don't, so add initializers for each of the | ||
|  |     // members specified in the POSIX std: | ||
|  |     stack_t sigstk = { 0, 0, 0 }; | ||
|  | #else | ||
|  |     stack_t sigstk = { }; | ||
|  | #endif | ||
|  | 
 | ||
|  |     sigstk.ss_size  = MINSIGSTKSZ; | ||
|  |     sigstk.ss_flags = SS_DISABLE; | ||
|  |     if( ::sigaltstack( &sigstk, 0 ) == -1 ) { | ||
|  |         int error_n = errno; | ||
|  |         std::cerr << "******** errors disabling the alternate stack:" << std::endl | ||
|  |                   << "\t#error:" << error_n << std::endl | ||
|  |                   << "\t" << std::strerror( error_n ) << std::endl; | ||
|  |     } | ||
|  | #endif | ||
|  | 
 | ||
|  |     s_active_handler = m_prev_handler; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************       execution_monitor_signal_handler       ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | extern "C" { | ||
|  | 
 | ||
|  | static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) | ||
|  | { | ||
|  |     signal_handler::sys_sig()( info, context ); | ||
|  | 
 | ||
|  |     siglongjmp( signal_handler::jump_buffer(), sig ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) | ||
|  | { | ||
|  |     if( !debug::attach_debugger( false ) ) | ||
|  |         boost_execution_monitor_jumping_signal_handler( sig, info, context ); | ||
|  | 
 | ||
|  |     // debugger attached; it will handle the signal | ||
|  |     BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace detail | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************        execution_monitor::catch_signals      ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | int | ||
|  | execution_monitor::catch_signals( boost::function<int ()> const& F ) | ||
|  | { | ||
|  |     using namespace detail; | ||
|  | 
 | ||
|  | #if defined(__CYGWIN__) | ||
|  |     p_catch_system_errors.value = false; | ||
|  | #endif | ||
|  | 
 | ||
|  | #ifdef BOOST_TEST_USE_ALT_STACK | ||
|  |     if( !!p_use_alt_stack && !m_alt_stack ) | ||
|  |         m_alt_stack.reset( new char[BOOST_TEST_ALT_STACK_SIZE] ); | ||
|  | #else | ||
|  |     p_use_alt_stack.value = false; | ||
|  | #endif | ||
|  | 
 | ||
|  |     signal_handler local_signal_handler( p_catch_system_errors, | ||
|  |                                          p_catch_system_errors || (p_detect_fp_exceptions != fpe::BOOST_FPE_OFF), | ||
|  |                                          p_timeout, | ||
|  |                                          p_auto_start_dbg, | ||
|  |                                          !p_use_alt_stack ? 0 : m_alt_stack.get() ); | ||
|  | 
 | ||
|  |     if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) ) | ||
|  |         return detail::do_invoke( m_custom_translators , F ); | ||
|  |     else | ||
|  |         BOOST_TEST_I_THROW( local_signal_handler.sys_sig() ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************   Microsoft structured exception handling    ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) | ||
|  | namespace { void _set_se_translator( void* ) {} } | ||
|  | #endif | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************    boost::detail::system_signal_exception    ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | class system_signal_exception { | ||
|  | public: | ||
|  |     // Constructor | ||
|  |     explicit            system_signal_exception( execution_monitor* em ) | ||
|  |     : m_em( em ) | ||
|  |     , m_se_id( 0 ) | ||
|  |     , m_fault_address( 0 ) | ||
|  |     , m_dir( false ) | ||
|  |     {} | ||
|  | 
 | ||
|  |     void                report() const; | ||
|  |     int                 operator()( unsigned id, _EXCEPTION_POINTERS* exps ); | ||
|  | 
 | ||
|  | private: | ||
|  |     // Data members | ||
|  |     execution_monitor*  m_em; | ||
|  | 
 | ||
|  |     unsigned            m_se_id; | ||
|  |     void*               m_fault_address; | ||
|  |     bool                m_dir; | ||
|  | }; | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) | ||
|  | static void | ||
|  | seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ ) | ||
|  | { | ||
|  |     throw; | ||
|  | } | ||
|  | #endif | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | int | ||
|  | system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps ) | ||
|  | { | ||
|  |     const unsigned MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC | ||
|  | 
 | ||
|  |     // C++ exception - allow to go through | ||
|  |     if( id == MSFT_CPP_EXCEPT ) | ||
|  |         return EXCEPTION_CONTINUE_SEARCH; | ||
|  | 
 | ||
|  |     // FPE detection is enabled, while system exception detection is not - check if this is actually FPE | ||
|  |     if( !m_em->p_catch_system_errors ) { | ||
|  |         if( !m_em->p_detect_fp_exceptions ) | ||
|  |             return EXCEPTION_CONTINUE_SEARCH; | ||
|  | 
 | ||
|  |         switch( id ) { | ||
|  |         case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
|  |         case EXCEPTION_FLT_STACK_CHECK: | ||
|  |         case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
|  |         case EXCEPTION_FLT_INEXACT_RESULT: | ||
|  |         case EXCEPTION_FLT_OVERFLOW: | ||
|  |         case EXCEPTION_FLT_UNDERFLOW: | ||
|  |         case EXCEPTION_FLT_INVALID_OPERATION: | ||
|  |         case STATUS_FLOAT_MULTIPLE_FAULTS: | ||
|  |         case STATUS_FLOAT_MULTIPLE_TRAPS: | ||
|  |             break; | ||
|  |         default: | ||
|  |             return EXCEPTION_CONTINUE_SEARCH; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) { | ||
|  |         m_em->p_catch_system_errors.value = false; | ||
|  | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) | ||
|  |         _set_se_translator( &seh_catch_preventer ); | ||
|  | #endif | ||
|  |         return EXCEPTION_CONTINUE_EXECUTION; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_se_id = id; | ||
|  |     if( m_se_id == EXCEPTION_ACCESS_VIOLATION && exps->ExceptionRecord->NumberParameters == 2 ) { | ||
|  |         m_fault_address = (void*)exps->ExceptionRecord->ExceptionInformation[1]; | ||
|  |         m_dir           = exps->ExceptionRecord->ExceptionInformation[0] == 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     return EXCEPTION_EXECUTE_HANDLER; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | void | ||
|  | system_signal_exception::report() const | ||
|  | { | ||
|  |     switch( m_se_id ) { | ||
|  |     // cases classified as system_fatal_error | ||
|  |     case EXCEPTION_ACCESS_VIOLATION: { | ||
|  |         if( !m_fault_address ) | ||
|  |             detail::report_error( execution_exception::system_fatal_error, "memory access violation" ); | ||
|  |         else | ||
|  |             detail::report_error( | ||
|  |                 execution_exception::system_fatal_error, | ||
|  |                     "memory access violation occurred at address 0x%08lx, while attempting to %s", | ||
|  |                     m_fault_address, | ||
|  |                     m_dir ? " read inaccessible data" | ||
|  |                           : " write to an inaccessible (or protected) address" | ||
|  |                     ); | ||
|  |         break; | ||
|  |     } | ||
|  | 
 | ||
|  |     case EXCEPTION_ILLEGAL_INSTRUCTION: | ||
|  |         detail::report_error( execution_exception::system_fatal_error, "illegal instruction" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_PRIV_INSTRUCTION: | ||
|  |         detail::report_error( execution_exception::system_fatal_error, "tried to execute an instruction whose operation is not allowed in the current machine mode" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_IN_PAGE_ERROR: | ||
|  |         detail::report_error( execution_exception::system_fatal_error, "access to a memory page that is not present" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_STACK_OVERFLOW: | ||
|  |         detail::report_error( execution_exception::system_fatal_error, "stack overflow" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_NONCONTINUABLE_EXCEPTION: | ||
|  |         detail::report_error( execution_exception::system_fatal_error, "tried to continue execution after a non continuable exception occurred" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     // cases classified as (non-fatal) system_trap | ||
|  |     case EXCEPTION_DATATYPE_MISALIGNMENT: | ||
|  |         detail::report_error( execution_exception::system_error, "data misalignment" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||
|  |         detail::report_error( execution_exception::system_error, "integer divide by zero" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_INT_OVERFLOW: | ||
|  |         detail::report_error( execution_exception::system_error, "integer overflow" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||
|  |         detail::report_error( execution_exception::system_error, "array bounds exceeded" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
|  |         detail::report_error( execution_exception::system_error, "floating point divide by zero" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_STACK_CHECK: | ||
|  |         detail::report_error( execution_exception::system_error, | ||
|  |                               "stack overflowed or underflowed as the result of a floating-point operation" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
|  |         detail::report_error( execution_exception::system_error, | ||
|  |                               "operand of floating point operation is denormal" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_INEXACT_RESULT: | ||
|  |         detail::report_error( execution_exception::system_error, | ||
|  |                               "result of a floating-point operation cannot be represented exactly" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_OVERFLOW: | ||
|  |         detail::report_error( execution_exception::system_error, | ||
|  |                               "exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_UNDERFLOW: | ||
|  |         detail::report_error( execution_exception::system_error, | ||
|  |                               "exponent of a floating-point operation is less than the magnitude allowed by the corresponding type" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_FLT_INVALID_OPERATION: | ||
|  |         detail::report_error( execution_exception::system_error, "floating point error" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case STATUS_FLOAT_MULTIPLE_FAULTS: | ||
|  |         detail::report_error( execution_exception::system_error, "multiple floating point errors" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case STATUS_FLOAT_MULTIPLE_TRAPS: | ||
|  |         detail::report_error( execution_exception::system_error, "multiple floating point errors" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     case EXCEPTION_BREAKPOINT: | ||
|  |         detail::report_error( execution_exception::system_error, "breakpoint encountered" ); | ||
|  |         break; | ||
|  | 
 | ||
|  |     default: | ||
|  |         detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id ); | ||
|  |         break; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************          assert_reporting_function           ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | int BOOST_TEST_CALL_DECL | ||
|  | assert_reporting_function( int reportType, char* userMessage, int* ) | ||
|  | { | ||
|  |     // write this way instead of switch to avoid unreachable statements | ||
|  |     if( reportType == BOOST_TEST_CRT_ASSERT || reportType == BOOST_TEST_CRT_ERROR ) | ||
|  |         detail::report_error( reportType == BOOST_TEST_CRT_ASSERT ? execution_exception::user_error : execution_exception::system_error, userMessage ); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } // assert_reporting_function | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | void BOOST_TEST_CALL_DECL | ||
|  | invalid_param_handler( wchar_t const* /* expr */, | ||
|  |                        wchar_t const* /* func */, | ||
|  |                        wchar_t const* /* file */, | ||
|  |                        unsigned       /* line */, | ||
|  |                        uintptr_t      /* reserved */) | ||
|  | { | ||
|  |     detail::report_error( execution_exception::user_error, | ||
|  |                           "Invalid parameter detected by C runtime library" ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | } // namespace detail | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************        execution_monitor::catch_signals      ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | int | ||
|  | execution_monitor::catch_signals( boost::function<int ()> const& F ) | ||
|  | { | ||
|  |     _invalid_parameter_handler old_iph = _invalid_parameter_handler(); | ||
|  |     BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0; | ||
|  | 
 | ||
|  |     if( p_catch_system_errors ) { | ||
|  |         old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); | ||
|  | 
 | ||
|  |         old_iph = _set_invalid_parameter_handler( | ||
|  |             reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); | ||
|  |     } else if( !p_detect_fp_exceptions ) { | ||
|  | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) | ||
|  |         _set_se_translator( &detail::seh_catch_preventer ); | ||
|  | #endif | ||
|  |     } | ||
|  | 
 | ||
|  |     detail::system_signal_exception SSE( this ); | ||
|  | 
 | ||
|  |     int ret_val = 0; | ||
|  |     // clang windows workaround: this not available in __finally scope | ||
|  |     bool l_catch_system_errors = p_catch_system_errors; | ||
|  | 
 | ||
|  |     __try { | ||
|  |         __try { | ||
|  |             ret_val = detail::do_invoke( m_custom_translators, F ); | ||
|  |         } | ||
|  |         __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) { | ||
|  |             throw SSE; | ||
|  |         } | ||
|  |     } | ||
|  |     __finally { | ||
|  |         if( l_catch_system_errors ) { | ||
|  |             BOOST_TEST_CRT_SET_HOOK( old_crt_hook ); | ||
|  | 
 | ||
|  |            _set_invalid_parameter_handler( old_iph ); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return ret_val; | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #else  // default signal handler | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | class system_signal_exception { | ||
|  | public: | ||
|  |     void   report() const {} | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace detail | ||
|  | 
 | ||
|  | int | ||
|  | execution_monitor::catch_signals( boost::function<int ()> const& F ) | ||
|  | { | ||
|  |     return detail::do_invoke( m_custom_translators , F ); | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #endif  // choose signal handler | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************              execution_monitor               ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | execution_monitor::execution_monitor() | ||
|  | : p_catch_system_errors( true ) | ||
|  | , p_auto_start_dbg( false ) | ||
|  | , p_timeout( 0 ) | ||
|  | , p_use_alt_stack( true ) | ||
|  | , p_detect_fp_exceptions( fpe::BOOST_FPE_OFF ) | ||
|  | {} | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | int | ||
|  | execution_monitor::execute( boost::function<int ()> const& F ) | ||
|  | { | ||
|  |     if( debug::under_debugger() ) | ||
|  |         p_catch_system_errors.value = false; | ||
|  | 
 | ||
|  |     BOOST_TEST_I_TRY { | ||
|  |         detail::fpe_except_guard G( p_detect_fp_exceptions ); | ||
|  |         unit_test::ut_detail::ignore_unused_variable_warning( G ); | ||
|  | 
 | ||
|  |         return catch_signals( F ); | ||
|  |     } | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_EXCEPTIONS | ||
|  | 
 | ||
|  |     //  Catch-clause reference arguments are a bit different from function | ||
|  |     //  arguments (ISO 15.3 paragraphs 18 & 19).  Apparently const isn't | ||
|  |     //  required.  Programmers ask for const anyhow, so we supply it.  That's | ||
|  |     //  easier than answering questions about non-const usage. | ||
|  | 
 | ||
|  |     catch( char const* ex ) | ||
|  |       { detail::report_error( execution_exception::cpp_exception_error, | ||
|  |                               "C string: %s", ex ); } | ||
|  |     catch( std::string const& ex ) | ||
|  |       { detail::report_error( execution_exception::cpp_exception_error, | ||
|  |                               "std::string: %s", ex.c_str() ); } | ||
|  | 
 | ||
|  |     //  std:: exceptions | ||
|  | #if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI) | ||
|  | #define CATCH_AND_REPORT_STD_EXCEPTION( ex_name )                           \ | ||
|  |     catch( ex_name const& ex )                                              \ | ||
|  |        { detail::report_error( execution_exception::cpp_exception_error,    \ | ||
|  |                           current_exception_cast<boost::exception const>(), \ | ||
|  |                           #ex_name ": %s", ex.what() ); }                   \ | ||
|  | /**/ | ||
|  | #else | ||
|  | #define CATCH_AND_REPORT_STD_EXCEPTION( ex_name )                           \ | ||
|  |     catch( ex_name const& ex )                                              \ | ||
|  |         { detail::report_error( execution_exception::cpp_exception_error,   \ | ||
|  |                           current_exception_cast<boost::exception const>(), \ | ||
|  |                           "%s: %s", detail::typeid_name(ex).c_str(), ex.what() ); } \ | ||
|  | /**/ | ||
|  | #endif | ||
|  | 
 | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc ) | ||
|  | 
 | ||
|  | #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) | ||
|  | #else | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) | ||
|  | #endif | ||
|  | 
 | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::bad_exception ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::domain_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::invalid_argument ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::length_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::out_of_range ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::range_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::overflow_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::underflow_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::logic_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::runtime_error ) | ||
|  |     CATCH_AND_REPORT_STD_EXCEPTION( std::exception ) | ||
|  | #undef CATCH_AND_REPORT_STD_EXCEPTION | ||
|  | 
 | ||
|  |     catch( boost::exception const& ex ) | ||
|  |       { detail::report_error( execution_exception::cpp_exception_error, | ||
|  |                               &ex, | ||
|  | #if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI) | ||
|  |                               "unknown boost::exception" ); } | ||
|  | #else | ||
|  |                               typeid(ex).name()          ); } | ||
|  | #endif | ||
|  | 
 | ||
|  |     // system errors | ||
|  |     catch( system_error const& ex ) | ||
|  |       { detail::report_error( execution_exception::cpp_exception_error, | ||
|  |                               "system_error produced by: %s: %s", ex.p_failed_exp, std::strerror( ex.p_errno ) ); } | ||
|  |     catch( detail::system_signal_exception const& ex ) | ||
|  |       { ex.report(); } | ||
|  | 
 | ||
|  |     // not an error | ||
|  |     catch( execution_aborted const& ) | ||
|  |       { return 0; } | ||
|  | 
 | ||
|  |     // just forward | ||
|  |     catch( execution_exception const& ) | ||
|  |       { throw; } | ||
|  | 
 | ||
|  |     // unknown error | ||
|  |     catch( ... ) | ||
|  |       { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); } | ||
|  | 
 | ||
|  | #endif // !BOOST_NO_EXCEPTION | ||
|  | 
 | ||
|  |     return 0;  // never reached; supplied to quiet compiler warnings | ||
|  | } // execute | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | struct forward { | ||
|  |     explicit    forward( boost::function<void ()> const& F ) : m_F( F ) {} | ||
|  | 
 | ||
|  |     int         operator()() { m_F(); return 0; } | ||
|  | 
 | ||
|  |     boost::function<void ()> const& m_F; | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace detail | ||
|  | void | ||
|  | execution_monitor::vexecute( boost::function<void ()> const& F ) | ||
|  | { | ||
|  |     execute( detail::forward( F ) ); | ||
|  | } | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************                  system_error                ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | system_error::system_error( char const* exp ) | ||
|  | #ifdef UNDER_CE | ||
|  | : p_errno( GetLastError() ) | ||
|  | #else | ||
|  | : p_errno( errno ) | ||
|  | #endif | ||
|  | , p_failed_exp( exp ) | ||
|  | {} | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************              execution_exception             ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | execution_exception::execution_exception( error_code ec_, const_string what_msg_, location const& location_ ) | ||
|  | : m_error_code( ec_ ) | ||
|  | , m_what( what_msg_.empty() ? BOOST_TEST_L( "uncaught exception, system error or abort requested" ) : what_msg_ ) | ||
|  | , m_location( location_ ) | ||
|  | {} | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | execution_exception::location::location( char const* file_name, size_t line_num, char const* func ) | ||
|  | : m_file_name( file_name ? file_name : "unknown location" ) | ||
|  | , m_line_num( line_num ) | ||
|  | , m_function( func ) | ||
|  | {} | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************Floating point exception management interface ************** // | ||
|  | // ************************************************************************** // | ||
|  | 
 | ||
|  | namespace fpe { | ||
|  | 
 | ||
|  | unsigned | ||
|  | enable( unsigned mask ) | ||
|  | { | ||
|  |     boost::ignore_unused(mask); | ||
|  | 
 | ||
|  | #if defined(UNDER_CE) | ||
|  |     /* Not Implemented in Windows CE */ | ||
|  |     return BOOST_FPE_OFF; | ||
|  | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) | ||
|  |     _clearfp(); | ||
|  | 
 | ||
|  | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) | ||
|  |     unsigned old_cw = ::_controlfp( 0, 0 ); | ||
|  |     ::_controlfp( old_cw & ~mask, BOOST_FPE_ALL ); | ||
|  | #else | ||
|  |     unsigned old_cw; | ||
|  |     if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) | ||
|  |         return BOOST_FPE_INV; | ||
|  | 
 | ||
|  |     // Set the control word | ||
|  |     if( ::_controlfp_s( 0, old_cw & ~mask, BOOST_FPE_ALL ) != 0 ) | ||
|  |         return BOOST_FPE_INV; | ||
|  | #endif | ||
|  | 
 | ||
|  |     return ~old_cw & BOOST_FPE_ALL; | ||
|  | #elif defined(__GLIBC__) && defined(__USE_GNU) | ||
|  |     if (BOOST_FPE_ALL == BOOST_FPE_OFF) | ||
|  |         /* Not Implemented */ | ||
|  |         return BOOST_FPE_OFF; | ||
|  |     feclearexcept(BOOST_FPE_ALL); | ||
|  |     int res = feenableexcept( mask ); | ||
|  |     return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; | ||
|  | #else | ||
|  |     /* Not Implemented  */ | ||
|  |     return BOOST_FPE_OFF; | ||
|  | #endif | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | unsigned | ||
|  | disable( unsigned mask ) | ||
|  | { | ||
|  |     boost::ignore_unused(mask); | ||
|  | 
 | ||
|  | #if defined(UNDER_CE) | ||
|  |     /* Not Implemented in Windows CE */ | ||
|  |     return BOOST_FPE_INV; | ||
|  | #elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) | ||
|  |     _clearfp(); | ||
|  | 
 | ||
|  | #if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) | ||
|  |     unsigned old_cw = ::_controlfp( 0, 0 ); | ||
|  |     ::_controlfp( old_cw | mask, BOOST_FPE_ALL ); | ||
|  | #else | ||
|  |     unsigned old_cw; | ||
|  |     if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) | ||
|  |         return BOOST_FPE_INV; | ||
|  | 
 | ||
|  |     // Set the control word | ||
|  |     if( ::_controlfp_s( 0, old_cw | mask, BOOST_FPE_ALL ) != 0 ) | ||
|  |         return BOOST_FPE_INV; | ||
|  | #endif | ||
|  | 
 | ||
|  |     return ~old_cw & BOOST_FPE_ALL; | ||
|  | #elif defined(__GLIBC__) && defined(__USE_GNU) | ||
|  |     if (BOOST_FPE_ALL == BOOST_FPE_OFF) | ||
|  |         /* Not Implemented */ | ||
|  |         return BOOST_FPE_INV; | ||
|  |     feclearexcept(BOOST_FPE_ALL); | ||
|  |     int res = fedisableexcept( mask ); | ||
|  |     return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; | ||
|  | #else | ||
|  |     /* Not Implemented */ | ||
|  |     return BOOST_FPE_INV; | ||
|  | #endif | ||
|  | } | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | } // namespace fpe | ||
|  | 
 | ||
|  | } // namespace boost | ||
|  | 
 | ||
|  | #include <boost/test/detail/enable_warnings.hpp> | ||
|  | 
 | ||
|  | #endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER |