diff -r 000000000000 -r e4d67989cc36 stdcpp/tsrc/Boost_test/test_framework/src/execution_monitor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stdcpp/tsrc/Boost_test/test_framework/src/execution_monitor.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,721 @@ +// (C) Copyright Gennadiy Rozental 2001-2005. +// (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: execution_monitor.ipp,v $ +// +// Version : $Revision: 1.13 $ +// +// 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. +// *************************************************************************** +/* + * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved. +*/ + +#ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER +#define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER + +// Boost.Test +#include +#include +#include + +// Boost +#include // for exit codes +#include // for workarounds + +// STL +#include // for std::string +#include // for std::bad_alloc +#include // for std::bad_cast, std::bad_typeid +#include // for std::exception, std::bad_exception +#include // for std exception hierarchy +#include // for C string API +#include // for assert +#include // for NULL + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::strlen; using ::strncat; } +#endif + +// Microsoft + other compatible compilers such as Intel + +#if !defined(BOOST_DISABLE_WIN32) && \ + !defined(__BORLANDC__) && \ + (defined(_MSC_VER) && !defined(__COMO__)) || \ + !(defined(__SYMBIAN32__)) + + + //(BOOST_WORKAROUND(__MWERKS__, >= 0x3000) && defined(__INTEL__)) && \ + +# define BOOST_MS_STRUCTURED_EXCEPTION_HANDLING + +# ifndef _WIN32_WINNT +# ifdef _WINBASE_ +# warning Debugger check disabled. Either define _WIN32_WINNT or include Boost.Test header in front of winbase.h +# else +# define BOOST_TEST_DEBUGGER_CHECK +# define _WIN32_WINNT 0x0400 +# endif +# endif + +# include +# include +# include +# include + +# if !defined(NDEBUG) && !defined(__MWERKS__) // __MWERKS__ does not seem to supply implementation of C runtime debug hooks, causing linking errors +# define BOOST_MS_CRT_DEBUG_HOOKS +# include +# endif + +#elif (defined(__BORLANDC__) && defined(_Windows) && !defined(BOOST_DISABLE_WIN32)) + +# define BOOST_MS_STRUCTURED_EXCEPTION_HANDLING +# include // Borland 5.5.1 has its own way of doing things. + +#elif defined(BOOST_HAS_SIGACTION) + +# define BOOST_SIGACTION_BASED_SIGNAL_HANDLING + +# include +# include +# include + +#else + +# define BOOST_NO_SIGNAL_HANDLING + +#endif + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace detail { + +using unit_test::const_string; + +// boost::execution_monitor::execute() calls boost::detail::report_error(...) to +// report any caught exception and throw execution_exception + +const std::size_t REPORT_ERROR_BUFFER_SIZE = 512; + +static void report_error( + execution_exception::error_code ec, + const_string msg1, // first part of the message + const_string msg2 = "" ); // second part of the message; sum length msg1 + msg2 should not + // exceed REPORT_ERROR_BUFFER_SIZE; never concatenate messages + // manually, cause it should work even in case of memory lack + +//____________________________________________________________________________// + +// Declaration for Microsoft structured exception handling (unix alternative - signal) +#ifdef BOOST_MS_STRUCTURED_EXCEPTION_HANDLING + +// this class defined per the Microsoft structured exception documentation +class ms_se_exception { +public: + // Constructor + EXPORT_C explicit ms_se_exception( unsigned int n ) + : m_se_id( n ) {} + + // Destructor + ~ms_se_exception() {} + + // access methods + EXPORT_C unsigned int id() const { return m_se_id; } + +private: + // Data members + unsigned int m_se_id; +}; + +//____________________________________________________________________________// + +void BOOST_TEST_CALL_DECL ms_se_trans_func( unsigned int id, _EXCEPTION_POINTERS* exps ); +void BOOST_TEST_CALL_DECL ms_se_forward_func( unsigned int id, _EXCEPTION_POINTERS* exps ); +static void report_ms_se_error( unsigned int id ); + +//____________________________________________________________________________// + +// Declarations for unix-style signal handling +#elif defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) + +class unix_signal_exception { + typedef execution_exception::error_code error_code_type; +public: + // Constructor + EXPORT_C unix_signal_exception( execution_exception::error_code ec, const_string em ) + : m_error_code( ec ), m_error_message( em ) {} + + // Destructor + ~unix_signal_exception() {} + + // access methods + EXPORT_C error_code_type error_code() const { return m_error_code; } + EXPORT_C const_string error_message() const { return m_error_message; } +private: + // Data members + error_code_type m_error_code; + const_string m_error_message; +}; + +#endif + +//____________________________________________________________________________// + +#if defined(BOOST_MS_CRT_DEBUG_HOOKS) + +EXPORT_C int +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 + } +} + +#endif + +} // namespace detail + +// ************************************************************************** // +// ************** execution_monitor ************** // +// ************************************************************************** // + +EXPORT_C int +execution_monitor::execute( unit_test::callback0 const& F, bool catch_system_errors, int timeout ) +{ + using unit_test::const_string; + +# ifdef BOOST_TEST_DEBUGGER_CHECK + if( IsDebuggerPresent() ) + catch_system_errors = false; +#endif + +#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) && !defined(__BORLANDC__) + if( catch_system_errors ) + _set_se_translator( detail::ms_se_trans_func ); + else + _set_se_translator( detail::ms_se_forward_func ); +#endif + +#ifdef BOOST_MS_CRT_DEBUG_HOOKS + if( catch_system_errors ) + _CrtSetReportHook( &detail::assert_reporting_function ); +#endif + + try { + return catch_signals( F, catch_system_errors, timeout ); + } + + // 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: ", ex ); } + catch( std::string const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::string: ", ex.c_str() ); } + + // std:: exceptions + + catch( std::bad_alloc const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::bad_alloc: ", ex.what() ); } +#ifndef __SYMBIAN32__ +#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 +#endif //__SYMBIAN32__ + catch( std::bad_cast const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::bad_cast: ", ex.what() ); } + catch( std::bad_typeid const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::bad_typeid: ", ex.what() ); } +#ifndef __SYMBIAN32__ +#endif //BOOST_WORKAROUND +#endif//__SYMBIAN32__ + + catch( std::bad_exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::bad_exception: ", ex.what() ); } + catch( std::domain_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::domain_error: ", ex.what() ); } + catch( std::invalid_argument const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::invalid_argument: ", ex.what() ); } + catch( std::length_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::length_error: ", ex.what() ); } + catch( std::out_of_range const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::out_of_range: ", ex.what() ); } + catch( std::range_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::range_error: ", ex.what() ); } + catch( std::overflow_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::overflow_error: ", ex.what() ); } + catch( std::underflow_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::underflow_error: ", ex.what() ); } + catch( std::logic_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::logic_error: ", ex.what() ); } + catch( std::runtime_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::runtime_error: ", ex.what() ); } + catch( std::exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, "std::exception: ", ex.what() ); } + +#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) + catch( detail::ms_se_exception const& ex ) + { detail::report_ms_se_error( ex.id() ); } +#elif defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) + catch( detail::unix_signal_exception const& ex ) + { detail::report_error( ex.error_code(), ex.error_message() ); } +#endif // BOOST_SIGACTION_BASED_SIGNAL_HANDLING + + 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 + +//____________________________________________________________________________// + +#if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) + +// ************************************************************************** // +// ************** boost::detail::signal_handler ************** // +// ************************************************************************** // + +namespace detail { + +class signal_handler { +public: + // Constructor + EXPORT_C explicit signal_handler( bool catch_system_errors, int timeout ); + + // Destructor + ~signal_handler(); + + // access methods + static sigjmp_buf& jump_buffer() + { + assert( !!s_active_handler ); + + return s_active_handler->m_sigjmp_buf; + } + +private: + // Data members + struct sigaction m_same_action_for_all_signals; + struct sigaction m_old_SIGFPE_action; + struct sigaction m_old_SIGTRAP_action; + struct sigaction m_old_SIGSEGV_action; + struct sigaction m_old_SIGBUS_action; + struct sigaction m_old_SIGABRT_action; + struct sigaction m_old_SIGALRM_action; + + sigjmp_buf m_sigjmp_buf; + + signal_handler* m_prev_handler; + static signal_handler* s_active_handler; + + bool m_catch_system_errors; + bool m_set_timeout; +}; + +signal_handler* signal_handler::s_active_handler = NULL; // !! need to be placed in thread specific storage + +//____________________________________________________________________________// + +extern "C" { + +static void execution_monitor_signal_handler( int sig ) +{ + siglongjmp( signal_handler::jump_buffer(), sig ); +} + +} + +//____________________________________________________________________________// + +signal_handler::signal_handler( bool catch_system_errors, int timeout ) +: m_prev_handler( s_active_handler ) +, m_catch_system_errors( catch_system_errors ) +, m_set_timeout( timeout > 0 ) +{ + s_active_handler = this; + + if( m_catch_system_errors || m_set_timeout ) { + m_same_action_for_all_signals.sa_flags = 0; + m_same_action_for_all_signals.sa_handler = &execution_monitor_signal_handler; + sigemptyset( &m_same_action_for_all_signals.sa_mask ); + } + + if( m_catch_system_errors ) { + sigaction( SIGFPE , &m_same_action_for_all_signals, &m_old_SIGFPE_action ); + sigaction( SIGTRAP, &m_same_action_for_all_signals, &m_old_SIGTRAP_action ); + sigaction( SIGSEGV, &m_same_action_for_all_signals, &m_old_SIGSEGV_action ); + sigaction( SIGBUS , &m_same_action_for_all_signals, &m_old_SIGBUS_action ); + sigaction( SIGABRT, &m_same_action_for_all_signals, &m_old_SIGABRT_action ); + } + + if( m_set_timeout ) { + sigaction( SIGALRM , &m_same_action_for_all_signals, &m_old_SIGALRM_action ); + alarm( timeout ); + } +} + +//____________________________________________________________________________// + +signal_handler::~signal_handler() +{ + typedef struct sigaction* sigaction_ptr; + + assert( s_active_handler == this ); + + if( m_set_timeout ) { + alarm( 0 ); + sigaction( SIGALRM, &m_old_SIGALRM_action, sigaction_ptr() ); + } + + if( m_catch_system_errors ) { + sigaction( SIGFPE , &m_old_SIGFPE_action , sigaction_ptr() ); + sigaction( SIGTRAP, &m_old_SIGTRAP_action, sigaction_ptr() ); + sigaction( SIGSEGV, &m_old_SIGSEGV_action, sigaction_ptr() ); + sigaction( SIGBUS , &m_old_SIGBUS_action , sigaction_ptr() ); + sigaction( SIGABRT, &m_old_SIGABRT_action, sigaction_ptr() ); + } + + s_active_handler = m_prev_handler; +} + +//____________________________________________________________________________// + +} // namespace detail + +// ************************************************************************** // +// ************** execution_monitor::catch_signals ************** // +// ************************************************************************** // + +EXPORT_C int +execution_monitor::catch_signals( unit_test::callback0 const& F, bool catch_system_errors, int timeout ) +{ + using namespace detail; + + signal_handler local_signal_handler( catch_system_errors, timeout ); + + volatile int sigtype = sigsetjmp( signal_handler::jump_buffer(), 1 ); + + typedef execution_exception::error_code ec_type; + int result = 0; + ec_type ec = execution_exception::no_error; + const_string em; + + if( sigtype == 0 ) { + result = m_custom_translators ? (*m_custom_translators)( F ) : F(); + } + else { + switch(sigtype) { + case SIGALRM: + ec = execution_exception::timeout_error; + em = BOOST_TEST_L( "signal: SIGALRM (timeout while executing function)" ); + break; + case SIGTRAP: + ec = execution_exception::system_error; + em = BOOST_TEST_L( "signal: SIGTRAP (perhaps integer divide by zero)" ); + break; + case SIGFPE: + ec = execution_exception::system_error; + em = BOOST_TEST_L( "signal: SIGFPE (arithmetic exception)" ); + break; + case SIGABRT: + ec = execution_exception::system_error; + em = BOOST_TEST_L( "signal: SIGABRT (application abort requested)" ); + break; + case SIGSEGV: + case SIGBUS: + ec = execution_exception::system_fatal_error; + em = BOOST_TEST_L( "memory access violation" ); + break; + default: + ec = execution_exception::system_error; + em = BOOST_TEST_L( "unrecognized signal" ); + } + } + + if( ec != execution_exception::no_error ) + throw unix_signal_exception( ec, em ); + + return result; +} // unix catch_signals + +//____________________________________________________________________________// + +#elif (defined(__BORLANDC__) && defined(_Windows) && !defined(BOOST_DISABLE_WIN32)) + +// this works for Borland but not other Win32 compilers (which trap too many cases) +EXPORT_C int +execution_monitor::catch_signals( unit_test::callback0 const& F, bool catch_system_errors, int ) +{ + int result; + + if( catch_system_errors ) { + __try { result = m_custom_translators ? (*m_custom_translators)( F ) : F(); } + + __except (1) { + throw detail::ms_se_exception( GetExceptionCode() ); + } + } + else + result = m_custom_translators ? (*m_custom_translators)( F ) : F(); + + return result; +} + +#else // default signal handler + +EXPORT_C int +execution_monitor::catch_signals( unit_test::callback0 const& F, bool, int ) +{ + return m_custom_translators ? (*m_custom_translators)( F ) : F(); +} + +#endif // choose signal handler + +// ************************************************************************** // +// ************** Microsoft structured exception handling ************** // +// ************************************************************************** // + +#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) + +namespace detail { + +EXPORT_C void +ms_se_trans_func( unsigned int id, _EXCEPTION_POINTERS* /* exps */ ) +{ + throw ms_se_exception( id ); +} + +//____________________________________________________________________________// + +EXPORT_C void +ms_se_forward_func( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) +{ + throw; +} + +//____________________________________________________________________________// + +EXPORT_C void +report_ms_se_error( unsigned int id ) +{ + switch( id ) { + // cases classified as fatal_system_error + case EXCEPTION_ACCESS_VIOLATION: + detail::report_error( execution_exception::system_fatal_error, "memory access violation" ); + 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, "privileged instruction" ); + break; + + case EXCEPTION_IN_PAGE_ERROR: + detail::report_error( execution_exception::system_fatal_error, "memory page error" ); + break; + + case EXCEPTION_STACK_OVERFLOW: + detail::report_error( execution_exception::system_fatal_error, "stack overflow" ); + 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, "floating point stack check" ); + break; + + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + detail::report_error( execution_exception::system_error, "floating point error" ); + break; + + default: + detail::report_error( execution_exception::system_error, "unrecognized exception or signal" ); + break; + } // switch +} // report_ms_se_error + +//____________________________________________________________________________// + +} // namespace detail + +#endif // Microsoft structured exception handling + +// ************************************************************************** // +// ************** report_error ************** // +// ************************************************************************** // + +namespace detail { + +static void report_error( execution_exception::error_code ec, const_string msg1, const_string msg2 ) +{ + static char buf[REPORT_ERROR_BUFFER_SIZE]; + + buf[0] = '\0'; + + std::strncat( buf, msg1.begin(), sizeof(buf)-1 ); + std::strncat( buf, msg2.begin(), sizeof(buf) - msg1.size() - 1 ); + + throw execution_exception( ec, buf ); +} + +//____________________________________________________________________________// + +} // namespace detail + +// ************************************************************************** // +// ************** detect_memory_leaks ************** // +// ************************************************************************** // + +EXPORT_C void +detect_memory_leaks( bool on_off ) +{ + unit_test::ut_detail::ignore_unused_variable_warning( on_off ); + +#ifdef BOOST_MS_CRT_DEBUG_HOOKS + int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); + + if( !on_off ) + flags &= ~_CRTDBG_LEAK_CHECK_DF; + else { + flags |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + } + + _CrtSetDbgFlag ( flags ); +#endif // BOOST_MS_CRT_DEBUG_HOOKS +} + +//____________________________________________________________________________// + +EXPORT_C void +break_memory_alloc( long mem_alloc_order_num ) +{ + unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num ); + +#ifdef BOOST_MS_CRT_DEBUG_HOOKS + _CrtSetBreakAlloc( mem_alloc_order_num ); +#endif // BOOST_MS_CRT_DEBUG_HOOKS +} + +} // namespace boost + +//____________________________________________________________________________// + +#include + +// *************************************************************************** +// Revision History : +// +// $Log: execution_monitor.ipp,v $ +// Revision 1.13 2006/02/22 16:14:45 rogeeff +// reagance to eliminate warning +// +// Revision 1.12 2006/01/30 07:29:49 rogeeff +// split memory leaks detection API in two to get more functions with better defined roles +// +// Revision 1.11 2006/01/15 09:47:43 rogeeff +// make common message +// +// Revision 1.10 2005/12/14 05:52:49 rogeeff +// *** empty log message *** +// +// Revision 1.9 2005/04/30 17:07:22 rogeeff +// ignore_warning included +// +// Revision 1.8 2005/04/30 16:46:50 rogeeff +// warning suppressed +// +// Revision 1.7 2005/04/13 05:32:03 rogeeff +// typo fix +// +// Revision 1.6 2005/04/05 06:11:37 rogeeff +// memory leak allocation point detection\nextra help with _WIN32_WINNT +// +// Revision 1.5 2005/02/20 08:27:07 rogeeff +// This a major update for Boost.Test framework. See release docs for complete list of fixes/updates +// +// Revision 1.4 2005/02/01 06:40:07 rogeeff +// copyright update +// old log entries removed +// minor stilistic changes +// depricated tools removed +// +// Revision 1.3 2005/01/31 07:50:06 rogeeff +// cdecl portability fix +// +// Revision 1.2 2005/01/31 05:58:03 rogeeff +// detect_memory_leak feature added +// +// Revision 1.1 2005/01/22 19:22:12 rogeeff +// implementation moved into headers section to eliminate dependency of included/minimal component on src directory +// +// Revision 1.36 2005/01/21 07:21:38 rogeeff +// detect presence of debugger under VC and automatically prevent catching system errors +// +// *************************************************************************** + +#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER