diff options
Diffstat (limited to 'boost/test/impl/execution_monitor.ipp')
-rw-r--r-- | boost/test/impl/execution_monitor.ipp | 635 |
1 files changed, 353 insertions, 282 deletions
diff --git a/boost/test/impl/execution_monitor.ipp b/boost/test/impl/execution_monitor.ipp index 07484b19d9..9929f74b53 100644 --- a/boost/test/impl/execution_monitor.ipp +++ b/boost/test/impl/execution_monitor.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // (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 @@ -27,14 +27,18 @@ // 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 @@ -48,6 +52,8 @@ #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 @@ -59,17 +65,12 @@ namespace std { using ::strerror; using ::strlen; using ::strncat; } using std::va_list; #endif -// to use vsnprintf -#if defined(__QNXNTO__) -# include <stdio.h> +// to use vsnprintf +#if defined(__QNXNTO__) +# include <stdio.h> #endif -#if defined(_WIN32) && !defined(BOOST_DISABLE_WIN32) && \ - (!defined(__COMO__) && !defined(__MWERKS__) && !defined(__GNUC__) || \ - BOOST_WORKAROUND(__MWERKS__, >= 0x3000)) - -# define BOOST_SEH_BASED_SIGNAL_HANDLING - +#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING # include <windows.h> # if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) @@ -84,37 +85,12 @@ using std::va_list; typedef unsigned uintptr_t; # endif -# if BOOST_WORKAROUND(_MSC_VER, < 1300 ) || defined(UNDER_CE) -typedef void* uintptr_t; +# if defined(UNDER_CE) && BOOST_WORKAROUND(_MSC_VER, < 1500 ) + typedef void* uintptr_t; +# elif defined(UNDER_CE) +# include <crtdefs.h> # endif -// for the FP control routines -#include <float.h> - -#ifndef EM_INVALID -#define EM_INVALID _EM_INVALID -#endif - -#ifndef EM_DENORMAL -#define EM_DENORMAL _EM_DENORMAL -#endif - -#ifndef EM_ZERODIVIDE -#define EM_ZERODIVIDE _EM_ZERODIVIDE -#endif - -#ifndef EM_OVERFLOW -#define EM_OVERFLOW _EM_OVERFLOW -#endif - -#ifndef EM_UNDERFLOW -#define EM_UNDERFLOW _EM_UNDERFLOW -#endif - -#ifndef MCW_EM -#define MCW_EM _MCW_EM -#endif - # if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE) # include <crtdbg.h> # define BOOST_TEST_CRT_HOOK_TYPE _CRT_REPORT_HOOK @@ -128,7 +104,8 @@ typedef void* uintptr_t; # define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H) # endif -# if !BOOST_WORKAROUND(_MSC_VER, >= 1400 ) || defined(UNDER_CE) +# if (!BOOST_WORKAROUND(_MSC_VER, >= 1400 ) && \ + !defined(BOOST_COMO)) || defined(UNDER_CE) typedef void* _invalid_parameter_handler; @@ -154,7 +131,9 @@ namespace { void _set_se_translator( void* ) {} } # include <signal.h> # include <setjmp.h> -# if defined(__FreeBSD__) +# if defined(__FreeBSD__) + +# include <osreldate.h> # ifndef SIGPOLL # define SIGPOLL SIGIO @@ -168,13 +147,17 @@ namespace { void _set_se_translator( void* ) {} } # define ILL_COPROC ILL_FPOP_FAULT # define BOOST_TEST_LIMITED_SIGNAL_DETAILS -# define BOOST_TEST_IGNORE_SIGCHLD -# endif -# endif +# endif +# endif + +# if defined(__ANDROID__) +# include <android/api-level.h> +# endif -# if !defined(__CYGWIN__) && !defined(__QNXNTO__) -# define BOOST_TEST_USE_ALT_STACK +# if !defined(__CYGWIN__) && !defined(__QNXNTO__) && !defined(__bgq__) && \ + (!defined(__ANDROID__) || __ANDROID_API__ >= 8) +# define BOOST_TEST_USE_ALT_STACK # endif # if defined(SIGPOLL) && !defined(__CYGWIN__) && \ @@ -188,6 +171,7 @@ namespace { void _set_se_translator( void* ) {} } # define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ # endif + #else # define BOOST_NO_SIGNAL_HANDLING @@ -198,6 +182,10 @@ namespace { void _set_se_translator( void* ) {} } #include <errno.h> #endif +#if defined(__GNUC__) && !defined(BOOST_NO_TYPEID) +# include <cxxabi.h> +#endif + #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// @@ -205,6 +193,14 @@ namespace { void _set_se_translator( void* ) {} } namespace boost { // ************************************************************************** // +// ************** throw_exception ************** // +// ************************************************************************** // + +#ifdef BOOST_NO_EXCEPTION +void throw_exception( std::exception const & e ) { abort(); } +#endif + +// ************************************************************************** // // ************** report_error ************** // // ************************************************************************** // @@ -220,6 +216,8 @@ namespace detail { # 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 ) @@ -237,39 +235,41 @@ extract( boost::exception const* ex ) 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 = 512; + static const int REPORT_ERROR_BUFFER_SIZE = 4096; static char buf[REPORT_ERROR_BUFFER_SIZE]; - BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); + BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); buf[sizeof(buf)-1] = 0; va_end( *args ); - throw execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ), - extract<throw_line>( be ), + 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, char const* format, ... ) +report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) { va_list args; va_start( args, format ); - report_error( ec, 0, format, &args ); + report_error( ec, be, format, &args ); } +#endif + //____________________________________________________________________________// static void -report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) +report_error( execution_exception::error_code ec, char const* format, ... ) { va_list args; va_start( args, format ); - report_error( ec, be, format, &args ); + report_error( ec, 0, format, &args ); } //____________________________________________________________________________// @@ -283,6 +283,47 @@ do_invoke( Tr const& tr, Functor const& F ) //____________________________________________________________________________// +struct fpe_except_guard { + explicit fpe_except_guard( unsigned detect_fpe ) + : m_detect_fpe( detect_fpe ) + { + // prepare fp exceptions control + m_previosly_enabled = fpe::disable( fpe::BOOST_FPE_ALL ); + if( m_previosly_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_previosly_enabled != fpe::BOOST_FPE_INV ) + fpe::enable( m_previosly_enabled ); + } + + unsigned m_detect_fpe; + unsigned m_previosly_enabled; +}; + +#ifndef BOOST_NO_TYPEID + +// ************************************************************************** // +// ************** typeid_name ************** // +// ************************************************************************** // + +template<typename T> +char const* +typeid_name( T const& t ) +{ +#ifdef __GNUC__ + int status; + + return abi::__cxa_demangle( typeid(t).name(), 0, 0, &status ); +#else + return typeid(t).name(); +#endif +} +#endif + } // namespace detail #if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) @@ -398,10 +439,10 @@ system_signal_exception::report() const "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 ); + 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; @@ -505,48 +546,6 @@ system_signal_exception::report() const } break; - case SIGCHLD: - switch( m_sig_info->si_code ) { -#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS - case CLD_EXITED: - report_error( execution_exception::system_error, - "child has exited; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_KILLED: - report_error( execution_exception::system_error, - "child was killed; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_DUMPED: - report_error( execution_exception::system_error, - "child terminated abnormally; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_TRAPPED: - report_error( execution_exception::system_error, - "traced child has trapped; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_STOPPED: - report_error( execution_exception::system_error, - "child has stopped; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_CONTINUED: - report_error( execution_exception::system_error, - "stopped child had continued; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; -#endif - default: - report_error( execution_exception::system_error, - "signal: SIGCHLD, si_code: %d (child process has terminated; pid: %d; uid: %d; exit value: %d)", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status, m_sig_info->si_code ); - break; - } - break; - #if defined(BOOST_TEST_CATCH_SIGPOLL) case SIGPOLL: @@ -585,11 +584,11 @@ system_signal_exception::report() const break; #endif #endif - default: - report_error( execution_exception::system_error, - "signal: SIGPOLL, si_code: %d (asynchronous I/O event occured; band event %d)", - (int)m_sig_info->si_band, m_sig_info->si_code ); - break; + 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; @@ -606,7 +605,8 @@ system_signal_exception::report() const break; default: - report_error( execution_exception::system_error, "unrecognized signal" ); + report_error( execution_exception::system_error, + "unrecognized signal %d", m_sig_info->si_signo ); } } @@ -618,8 +618,8 @@ system_signal_exception::report() const // Forward declaration extern "C" { -static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); -static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); +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 { @@ -663,8 +663,8 @@ signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_ } m_new_action.sa_flags |= SA_SIGINFO; - m_new_action.sa_sigaction = attach_dbg ? &execution_monitor_attaching_signal_handler - : &execution_monitor_jumping_signal_handler; + 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 @@ -692,7 +692,7 @@ signal_action::~signal_action() class signal_handler { public: // Constructor - explicit signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ); + explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ); // Destructor ~signal_handler(); @@ -715,8 +715,9 @@ public: private: // Data members signal_handler* m_prev_handler; - int m_timeout; + 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; @@ -738,16 +739,13 @@ signal_handler* signal_handler::s_active_handler = signal_handler_ptr(); //____________________________________________________________________________// -signal_handler::signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ) +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 , 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 ) -#ifndef BOOST_TEST_IGNORE_SIGCHLD -, m_CHLD_action( SIGCHLD, catch_system_errors, attach_dbg, alt_stack ) -#endif #ifdef BOOST_TEST_CATCH_SIGPOLL , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) #endif @@ -799,7 +797,12 @@ signal_handler::~signal_handler() sigstk.ss_size = MINSIGSTKSZ; sigstk.ss_flags = SS_DISABLE; - BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); + 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; @@ -813,26 +816,8 @@ signal_handler::~signal_handler() extern "C" { -static bool ignore_sigchild( siginfo_t* info ) -{ - return info->si_signo == SIGCHLD -#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS - && info->si_code == CLD_EXITED -#endif -#ifdef BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE - ; -#else - && (int)info->si_status == 0; -#endif -} - -//____________________________________________________________________________// - -static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) +static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) { - if( ignore_sigchild( info ) ) - return; - signal_handler::sys_sig()( info, context ); siglongjmp( signal_handler::jump_buffer(), sig ); @@ -840,13 +825,10 @@ static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, //____________________________________________________________________________// -static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) +static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) { - if( ignore_sigchild( info ) ) - return; - if( !debug::attach_debugger( false ) ) - execution_monitor_jumping_signal_handler( sig, info, context ); + 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 ); @@ -863,7 +845,7 @@ static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info // ************************************************************************** // int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +execution_monitor::catch_signals( boost::function<int ()> const& F ) { using namespace detail; @@ -878,13 +860,16 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) p_use_alt_stack.value = false; #endif - signal_handler local_signal_handler( p_catch_system_errors, p_timeout, p_auto_start_dbg, + 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 - throw local_signal_handler.sys_sig(); + return BOOST_TEST_IMPL_THROW( local_signal_handler.sys_sig() ); } //____________________________________________________________________________// @@ -916,37 +901,64 @@ public: {} void report() const; - int operator()( unsigned int id, _EXCEPTION_POINTERS* exps ); + int operator()( unsigned id, _EXCEPTION_POINTERS* exps ); private: // Data members execution_monitor* m_em; - unsigned int m_se_id; + unsigned m_se_id; void* m_fault_address; bool m_dir; }; +//____________________________________________________________________________// + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) static void -seh_catch_preventer( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) +seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ ) { throw; } +#endif //____________________________________________________________________________// int -system_signal_exception::operator()( unsigned int id, _EXCEPTION_POINTERS* exps ) +system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps ) { - const unsigned int MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC + const unsigned MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC - if( !m_em->p_catch_system_errors || (id == MSFT_CPP_EXCEPT) ) + // 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; } @@ -1031,12 +1043,10 @@ system_signal_exception::report() const "operand of floating point operation is denormal" ); break; -# if 0 // !! ?? case EXCEPTION_FLT_INEXACT_RESULT: detail::report_error( execution_exception::system_error, "result of a floating-point operation cannot be represented exactly" ); break; -#endif case EXCEPTION_FLT_OVERFLOW: detail::report_error( execution_exception::system_error, @@ -1052,6 +1062,14 @@ system_signal_exception::report() const 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; @@ -1071,59 +1089,28 @@ system_signal_exception::report() const int BOOST_TEST_CALL_DECL assert_reporting_function( int reportType, char* userMessage, int* ) { - switch( reportType ) { - case BOOST_TEST_CRT_ASSERT: - detail::report_error( execution_exception::user_error, userMessage ); + // 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 1; // return value and retVal are not important since we never reach this line - case BOOST_TEST_CRT_ERROR: - detail::report_error( execution_exception::system_error, userMessage ); - - return 1; // return value and retVal are not important since we never reach this line - default: - return 0; // use usual reporting method - } + 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 int /* line */, +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, + detail::report_error( execution_exception::user_error, "Invalid parameter detected by C runtime library" ); } //____________________________________________________________________________// -void BOOST_TEST_CALL_DECL -switch_fp_exceptions( bool on_off ) -{ - if( !on_off ) - _clearfp(); - - int cw = ::_controlfp( 0, 0 ); - - int exceptions_mask = EM_INVALID|EM_DENORMAL|EM_ZERODIVIDE|EM_OVERFLOW|EM_UNDERFLOW; - - if( on_off ) - cw &= ~exceptions_mask; // Set the exception masks on, turn exceptions off - else - cw |= exceptions_mask; // Set the exception masks off, turn exceptions on - - if( on_off ) - _clearfp(); - - // Set the control word - ::_controlfp( cw, MCW_EM ); -} - -//____________________________________________________________________________// - } // namespace detail // ************************************************************************** // @@ -1131,25 +1118,24 @@ switch_fp_exceptions( bool on_off ) // ************************************************************************** // int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +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 ) - _set_se_translator( &detail::seh_catch_preventer ); - else { - if( !!p_detect_fp_exceptions ) - detail::switch_fp_exceptions( true ); - - old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); + 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 ) ); + 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; __try { @@ -1161,10 +1147,7 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) } } __finally { - if( !!p_catch_system_errors ) { - if( !!p_detect_fp_exceptions ) - detail::switch_fp_exceptions( false ); - + if( p_catch_system_errors ) { BOOST_TEST_CRT_SET_HOOK( old_crt_hook ); _set_invalid_parameter_handler( old_iph ); @@ -1188,7 +1171,7 @@ public: } // namespace detail int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +execution_monitor::catch_signals( boost::function<int ()> const& F ) { return detail::do_invoke( m_custom_translators , F ); } @@ -1198,19 +1181,34 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) #endif // choose signal handler // ************************************************************************** // -// ************** execution_monitor::execute ************** // +// ************** 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( unit_test::callback0<int> const& F ) +execution_monitor::execute( boost::function<int ()> const& F ) { if( debug::under_debugger() ) p_catch_system_errors.value = false; - try { + BOOST_TEST_IMPL_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_EXCEPTION + // 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 @@ -1220,89 +1218,61 @@ execution_monitor::execute( unit_test::callback0<int> const& F ) { 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, + { detail::report_error( execution_exception::cpp_exception_error, "std::string: %s", ex.c_str() ); } // std:: exceptions +#ifdef BOOST_NO_TYPEID +#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), ex.what() ); } \ +/**/ +#endif - catch( std::bad_alloc const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_alloc: %s", ex.what() ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc ) #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) - catch( std::bad_cast const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_cast" ); } - catch( std::bad_typeid const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_typeid" ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) #else - catch( std::bad_cast const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_cast: %s", ex.what() ); } - catch( std::bad_typeid const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_typeid: %s", ex.what() ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) #endif - catch( std::bad_exception const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_exception: %s", ex.what() ); } - catch( std::domain_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::domain_error: %s", ex.what() ); } - catch( std::invalid_argument const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::invalid_argument: %s", ex.what() ); } - catch( std::length_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::length_error: %s", ex.what() ); } - catch( std::out_of_range const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::out_of_range: %s", ex.what() ); } - catch( std::range_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::range_error: %s", ex.what() ); } - catch( std::overflow_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::overflow_error: %s", ex.what() ); } - catch( std::underflow_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::underflow_error: %s", ex.what() ); } - catch( std::logic_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::logic_error: %s", ex.what() ); } - catch( std::runtime_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::runtime_error: %s", ex.what() ); } - catch( std::exception const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::exception: %s", ex.what() ); } + 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, - "unknown boost::exception" ); } + { detail::report_error( execution_exception::cpp_exception_error, + &ex, +#ifdef BOOST_NO_TYPEID + "unknown boost::exception" ); } +#else + typeid(ex).name() ); } +#endif // system errors catch( system_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, + { detail::report_error( execution_exception::cpp_exception_error, "system_error produced by: %s: %s", ex.p_failed_exp.get(), std::strerror( ex.p_errno ) ); } catch( detail::system_signal_exception const& ex ) { ex.report(); } @@ -1319,11 +1289,30 @@ execution_monitor::execute( unit_test::callback0<int> const& F ) 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 ************** // // ************************************************************************** // @@ -1359,6 +1348,88 @@ execution_exception::location::location( char const* file_name, size_t line_num, //____________________________________________________________________________// +// ************************************************************************** // +// **************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 0; +#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) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) + ::feclearexcept(BOOST_FPE_ALL); + int res = ::feenableexcept( mask ); + return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; +#else + /* Not Implemented */ + return 0; +#endif +} + +//____________________________________________________________________________// + +unsigned +disable( unsigned mask ) +{ + boost::ignore_unused(mask); + +#if defined(UNDER_CE) + /* Not Implemented in Windows CE */ + return 0; +#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) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) + ::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> |