diff options
Diffstat (limited to 'src/third_party/boost-1.56.0/boost/test/impl/execution_monitor.ipp')
-rw-r--r-- | src/third_party/boost-1.56.0/boost/test/impl/execution_monitor.ipp | 1367 |
1 files changed, 1367 insertions, 0 deletions
diff --git a/src/third_party/boost-1.56.0/boost/test/impl/execution_monitor.ipp b/src/third_party/boost-1.56.0/boost/test/impl/execution_monitor.ipp new file mode 100644 index 00000000000..07484b19d95 --- /dev/null +++ b/src/third_party/boost-1.56.0/boost/test/impl/execution_monitor.ipp @@ -0,0 +1,1367 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : 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/execution_monitor.hpp> +#include <boost/test/debug.hpp> + +// Boost +#include <boost/cstdlib.hpp> // for exit codes +#include <boost/config.hpp> // for workarounds +#include <boost/exception/get_error_info.hpp> // for get_error_info +#include <boost/exception/current_exception_cast.hpp> // for current_exception_cast + +// 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 + +#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> +#endif + +#if defined(_WIN32) && !defined(BOOST_DISABLE_WIN32) && \ + (!defined(__COMO__) && !defined(__MWERKS__) && !defined(__GNUC__) || \ + BOOST_WORKAROUND(__MWERKS__, >= 0x3000)) + +# define 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 BOOST_WORKAROUND(_MSC_VER, < 1300 ) || defined(UNDER_CE) +typedef void* uintptr_t; +# 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 +# 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(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__) + +# 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 +# define BOOST_TEST_IGNORE_SIGCHLD + +# endif +# endif + +# if !defined(__CYGWIN__) && !defined(__QNXNTO__) +# 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 + +#include <boost/test/detail/suppress_warnings.hpp> + +//____________________________________________________________________________// + +namespace boost { + +// ************************************************************************** // +// ************** 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 + +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 = 512; + static char buf[REPORT_ERROR_BUFFER_SIZE]; + + 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 ), + extract<throw_function>( be ) ) ); +} + +//____________________________________________________________________________// + +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 ); +} + +//____________________________________________________________________________// + +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 ); +} + +//____________________________________________________________________________// + +template<typename Tr,typename Functor> +inline int +do_invoke( Tr const& tr, Functor const& F ) +{ + return tr ? (*tr)( F ) : F(); +} + +//____________________________________________________________________________// + +} // 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; + + 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: + 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 occured; 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" ); + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** boost::detail::signal_action ************** // +// ************************************************************************** // + +// 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 ); +} + +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 ? &execution_monitor_attaching_signal_handler + : &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, int 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; + int m_timeout; + + 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, int 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_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 +, 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; + BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); +#endif + + s_active_handler = m_prev_handler; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** execution_monitor_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 ) +{ + if( ignore_sigchild( info ) ) + return; + + signal_handler::sys_sig()( info, context ); + + siglongjmp( signal_handler::jump_buffer(), sig ); +} + +//____________________________________________________________________________// + +static void 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 ); + + // 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( unit_test::callback0<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_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(); +} + +//____________________________________________________________________________// + +#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 int id, _EXCEPTION_POINTERS* exps ); + +private: + // Data members + execution_monitor* m_em; + + unsigned int m_se_id; + void* m_fault_address; + bool m_dir; +}; + +static void +seh_catch_preventer( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) +{ + throw; +} + +//____________________________________________________________________________// + +int +system_signal_exception::operator()( unsigned int id, _EXCEPTION_POINTERS* exps ) +{ + const unsigned int MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC + + if( !m_em->p_catch_system_errors || (id == MSFT_CPP_EXCEPT) ) + return EXCEPTION_CONTINUE_SEARCH; + + if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) { + m_em->p_catch_system_errors.value = false; + _set_se_translator( &seh_catch_preventer ); + + 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; + +# 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, + "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 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* ) +{ + switch( reportType ) { + case BOOST_TEST_CRT_ASSERT: + detail::report_error( execution_exception::user_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 + } +} // 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 */, + uintptr_t /* reserved */) +{ + 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 + +// ************************************************************************** // +// ************** execution_monitor::catch_signals ************** // +// ************************************************************************** // + +int +execution_monitor::catch_signals( unit_test::callback0<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 ); + + old_iph = _set_invalid_parameter_handler( + reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); + } + + detail::system_signal_exception SSE( this ); + + int ret_val = 0; + + __try { + __try { + ret_val = detail::do_invoke( m_custom_translators, F ); + } + __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) { + throw SSE; + } + } + __finally { + if( !!p_catch_system_errors ) { + if( !!p_detect_fp_exceptions ) + detail::switch_fp_exceptions( false ); + + 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( unit_test::callback0<int> const& F ) +{ + return detail::do_invoke( m_custom_translators , F ); +} + +//____________________________________________________________________________// + +#endif // choose signal handler + +// ************************************************************************** // +// ************** execution_monitor::execute ************** // +// ************************************************************************** // + +int +execution_monitor::execute( unit_test::callback0<int> const& F ) +{ + if( debug::under_debugger() ) + p_catch_system_errors.value = false; + + try { + return catch_signals( F ); + } + + // 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 + + 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() ); } + +#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" ); } +#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() ); } +#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( boost::exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + &ex, + "unknown boost::exception" ); } + + // 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.get(), 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" ); } + + return 0; // never reached; supplied to quiet compiler warnings +} // execute + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** 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 ) +{} + +//____________________________________________________________________________// + +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER + |