12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367 |
- // (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: 57992 $
- //
- // 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
|