| // (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 <ndnboost/test/detail/config.hpp> |
| #include <ndnboost/test/detail/workaround.hpp> |
| #include <ndnboost/test/execution_monitor.hpp> |
| #include <ndnboost/test/debug.hpp> |
| |
| // Boost |
| #include <ndnboost/cstdlib.hpp> // for exit codes |
| #include <ndnboost/config.hpp> // for workarounds |
| #include <ndnboost/exception/get_error_info.hpp> // for get_error_info |
| #include <ndnboost/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 <ndnboost/test/detail/suppress_warnings.hpp> |
| |
| //____________________________________________________________________________// |
| |
| namespace ndnboost { |
| |
| // ************************************************************************** // |
| // ************** 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( ndnboost::exception const* ex ) |
| { |
| if( !ex ) |
| return 0; |
| |
| typename ErrorInfo::value_type const * val = ndnboost::get_error_info<ErrorInfo>( *ex ); |
| |
| return val ? *val : 0; |
| } |
| |
| //____________________________________________________________________________// |
| |
| static void |
| report_error( execution_exception::error_code ec, ndnboost::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, ndnboost::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 { |
| |
| // ************************************************************************** // |
| // ************** ndnboost::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" ); |
| } |
| } |
| |
| //____________________________________________________________________________// |
| |
| // ************************************************************************** // |
| // ************** ndnboost::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() ); |
| } |
| |
| //____________________________________________________________________________// |
| |
| // ************************************************************************** // |
| // ************** ndnboost::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 { |
| |
| // ************************************************************************** // |
| // ************** ndnboost::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<ndnboost::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<ndnboost::exception const>(), |
| "std::bad_cast" ); } |
| catch( std::bad_typeid const& ex ) |
| { detail::report_error( execution_exception::cpp_exception_error, |
| current_exception_cast<ndnboost::exception const>(), |
| "std::bad_typeid" ); } |
| #else |
| catch( std::bad_cast const& ex ) |
| { detail::report_error( execution_exception::cpp_exception_error, |
| current_exception_cast<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::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<ndnboost::exception const>(), |
| "std::runtime_error: %s", ex.what() ); } |
| catch( std::exception const& ex ) |
| { detail::report_error( execution_exception::cpp_exception_error, |
| current_exception_cast<ndnboost::exception const>(), |
| "std::exception: %s", ex.what() ); } |
| |
| catch( ndnboost::exception const& ex ) |
| { detail::report_error( execution_exception::cpp_exception_error, |
| &ex, |
| "unknown ndnboost::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 ndnboost |
| |
| #include <ndnboost/test/detail/enable_warnings.hpp> |
| |
| #endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER |
| |