text: //  (C) Copyright Gennadiy Rozental 2001-2007.
  //  (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: 41369 $
  //
  //  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
  
  // 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
  
  #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__)
  #    include <eh.h>
  #  endif
  
  #  if defined(__BORLANDC__) || defined(__MWERKS__)
  #    include <stdint.h>
  #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)
  #    define BOOST_TEST_USE_DEBUG_MS_CRT
  #    include <crtdbg.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(__CYGWIN__)
  #   define BOOST_TEST_USE_ALT_STACK
  #  endif
  
  #  if !defined(__CYGWIN__) && !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
  #    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
  
  static void
  report_error( execution_exception::error_code ec, char const* format, ... )
  {
      static const int REPORT_ERROR_BUFFER_SIZE = 512;
      static char buf[REPORT_ERROR_BUFFER_SIZE];
  
      va_list args;
      va_start( args, format );
  
      BOOST_TEST_VSNPRINTF( buf, sizeof(buf), format, args );
      va_end( args );
  
      throw execution_exception( ec, buf );
  }
  
  //____________________________________________________________________________//
  
  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?
  
      if( m_sig_info->si_code <= 0 ) {
          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;
          }
      }
      else {
          switch( m_sig_info->si_signo ) {
          case SIGILL:
              switch( m_sig_info->si_code ) {
              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_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_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_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_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_COPROC:
                  report_error( execution_exception::system_fatal_error,
                                "signal: co-processor error; 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;
              }
              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;
              }
              break;
  
          case SIGSEGV:
              switch( m_sig_info->si_code ) {
              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;
              }
              break;
  
          case SIGBUS:
              switch( m_sig_info->si_code ) {
              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;
              }
              break;
  
          case SIGCHLD:
              switch( m_sig_info->si_code ) {
              case CLD_EXITED:
                  report_error( execution_exception::system_error,
                                "child has exited; pid: %d; uid: %d; exit value: %d",
                                (int)m_sig_info->si_uid, (int)m_sig_info->si_pid, (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_uid, (int)m_sig_info->si_pid, (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_uid, (int)m_sig_info->si_pid, (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_uid, (int)m_sig_info->si_pid, (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_uid, (int)m_sig_info->si_pid, (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_uid, (int)m_sig_info->si_pid, (int)m_sig_info->si_status );
                  break;
              }
              break;
  
  #if defined(BOOST_TEST_CATCH_SIGPOLL)
  
          case SIGPOLL:
              switch( m_sig_info->si_code ) {
              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;
              case POLL_HUP:
                  report_error( execution_exception::system_error,
                                "device disconnected; band event %d",
                                (int)m_sig_info->si_band );
                  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
      explicit            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( 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;
  #ifdef BOOST_TEST_CATCH_SIGPOLL
      signal_action           m_POLL_action;
  #endif
      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 )
  , m_CHLD_action( SIGCHLD, catch_system_errors, attach_dbg, alt_stack )
  #ifdef BOOST_TEST_CATCH_SIGPOLL
  , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack )
  #endif
  , m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack )
  , m_ALRM_action( SIGALRM, timeout > 0        , attach_dbg, alt_stack )
  {
      s_active_handler = this;
  
      if( m_timeout > 0 ) {
          ::alarm( 0 );
          ::alarm( timeout );
      }
  
  #ifdef BOOST_TEST_USE_ALT_STACK
      if( alt_stack ) {
          stack_t sigstk;
  
          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
      stack_t sigstk;
  
      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 void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context )
  {
      signal_handler::sys_sig()( info, context );
  
      siglongjmp( signal_handler::jump_buffer(), sig );
  }
  
  //____________________________________________________________________________//
  
  static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context )
  {
      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;
      }
  }
  
  //____________________________________________________________________________//
  
  #if defined(BOOST_TEST_USE_DEBUG_MS_CRT)
  
  // ************************************************************************** //
  // **************          assert_reporting_function           ************** //
  // ************************************************************************** //
  
  int BOOST_TEST_CALL_DECL
  assert_reporting_function( int reportType, char* userMessage, int* retVal )
  {
      switch( reportType ) {
      case _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 _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
  
  #endif
  
  //____________________________________________________________________________//
  
  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;
  
      if( !p_catch_system_errors )
          _set_se_translator( &detail::seh_catch_preventer );
      else {
          if( !!p_detect_fp_exceptions )
              detail::switch_fp_exceptions( true );
  
  #ifdef BOOST_TEST_USE_DEBUG_MS_CRT
         _CrtSetReportHook( &detail::assert_reporting_function );
  #endif
  
         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 );
  
             _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, "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, "std::bad_cast" ); }
      catch( std::bad_typeid const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::bad_typeid" ); }
  #else
      catch( std::bad_cast const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::bad_cast: %s", ex.what() ); }
      catch( std::bad_typeid const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::bad_typeid: %s", ex.what() ); }
  #endif
  
      catch( std::bad_exception const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::bad_exception: %s", ex.what() ); }
      catch( std::domain_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::domain_error: %s", ex.what() ); }
      catch( std::invalid_argument const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::invalid_argument: %s", ex.what() ); }
      catch( std::length_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::length_error: %s", ex.what() ); }
      catch( std::out_of_range const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::out_of_range: %s", ex.what() ); }
      catch( std::range_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::range_error: %s", ex.what() ); }
      catch( std::overflow_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::overflow_error: %s", ex.what() ); }
      catch( std::underflow_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::underflow_error: %s", ex.what() ); }
      catch( std::logic_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::logic_error: %s", ex.what() ); }
      catch( std::runtime_error const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::runtime_error: %s", ex.what() ); }
      catch( std::exception const& ex )
        { detail::report_error( execution_exception::cpp_exception_error, "std::exception: %s", ex.what() ); }
      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(); }
      catch( execution_aborted const& )
        { return 0; }
      catch( execution_exception const& )
        { throw; }
  
      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 )
  {}
  
  
  //____________________________________________________________________________//
  
  } // namespace boost
  
  //____________________________________________________________________________//
  
  #include <boost/test/detail/enable_warnings.hpp>
  
  #endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
  