1// (C) Copyright Gennadiy Rozental 2001-2005. 2// (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001. 3// Use, modification, and distribution are subject to the 4// Boost Software License, Version 1.0. (See accompanying file 5// http://www.boost.org/LICENSE_1_0.txt) 6 7// See http://www.boost.org/libs/test for the library home page. 8// 9// File : $RCSfile: execution_monitor.ipp,v $ 10// 11// Version : $Revision: 1.1.1.1 $ 12// 13// Description : provides execution monitor implementation for all supported 14// configurations, including Microsoft structured exception based, unix signals 15// based and special workarounds for borland 16// 17// Note that when testing requirements or user wishes preclude use of this 18// file as a separate compilation unit, it may be included as a header file. 19// 20// Header dependencies are deliberately restricted to reduce coupling to other 21// boost libraries. 22// *************************************************************************** 23 24#ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER 25#define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER 26 27// Boost.Test 28#include <boost/test/detail/config.hpp> 29#include <boost/test/detail/workaround.hpp> 30#include <boost/test/execution_monitor.hpp> 31 32// Boost 33#include <boost/cstdlib.hpp> // for exit codes 34#include <boost/config.hpp> // for workarounds 35 36// STL 37#include <string> // for std::string 38#include <new> // for std::bad_alloc 39#include <typeinfo> // for std::bad_cast, std::bad_typeid 40#include <exception> // for std::exception, std::bad_exception 41#include <stdexcept> // for std exception hierarchy 42#include <cstring> // for C string API 43#include <cassert> // for assert 44#include <cstddef> // for NULL 45 46#ifdef BOOST_NO_STDC_NAMESPACE 47namespace std { using ::strlen; using ::strncat; } 48#endif 49 50// Microsoft + other compatible compilers such as Intel 51#if !defined(BOOST_DISABLE_WIN32) && \ 52 !defined(__BORLANDC__) && \ 53 (defined(_MSC_VER) && !defined(__COMO__)) || \ 54 (BOOST_WORKAROUND(__MWERKS__, >= 0x3000) && defined(__INTEL__)) 55 56# define BOOST_MS_STRUCTURED_EXCEPTION_HANDLING 57 58# ifndef _WIN32_WINNT 59# ifdef _WINBASE_ 60# warning Debugger check disabled. Either define _WIN32_WINNT or include Boost.Test header in front of winbase.h 61# else 62# define BOOST_TEST_DEBUGGER_CHECK 63# define _WIN32_WINNT 0x0400 64# endif 65# endif 66 67# include <wtypes.h> 68# include <winbase.h> 69# include <excpt.h> 70# include <eh.h> 71 72# if !defined(NDEBUG) && !defined(__MWERKS__) // __MWERKS__ does not seem to supply implementation of C runtime debug hooks, causing linking errors 73# define BOOST_MS_CRT_DEBUG_HOOKS 74# include <crtdbg.h> 75# endif 76 77#elif (defined(__BORLANDC__) && defined(_Windows) && !defined(BOOST_DISABLE_WIN32)) 78 79# define BOOST_MS_STRUCTURED_EXCEPTION_HANDLING 80# include <windows.h> // Borland 5.5.1 has its own way of doing things. 81 82#elif defined(BOOST_HAS_SIGACTION) 83 84# define BOOST_SIGACTION_BASED_SIGNAL_HANDLING 85 86# include <unistd.h> 87# include <signal.h> 88# include <setjmp.h> 89 90#else 91 92# define BOOST_NO_SIGNAL_HANDLING 93 94#endif 95 96#include <boost/test/detail/suppress_warnings.hpp> 97 98//____________________________________________________________________________// 99 100namespace boost { 101 102namespace detail { 103 104using unit_test::const_string; 105 106// boost::execution_monitor::execute() calls boost::detail::report_error(...) to 107// report any caught exception and throw execution_exception 108 109const std::size_t REPORT_ERROR_BUFFER_SIZE = 512; 110 111static void report_error( 112 execution_exception::error_code ec, 113 const_string msg1, // first part of the message 114 const_string msg2 = "" ); // second part of the message; sum length msg1 + msg2 should not 115 // exceed REPORT_ERROR_BUFFER_SIZE; never concatenate messages 116 // manually, cause it should work even in case of memory lack 117 118//____________________________________________________________________________// 119 120// Declaration for Microsoft structured exception handling (unix alternative - signal) 121#ifdef BOOST_MS_STRUCTURED_EXCEPTION_HANDLING 122 123// this class defined per the Microsoft structured exception documentation 124class ms_se_exception { 125public: 126 // Constructor 127 explicit ms_se_exception( unsigned int n ) 128 : m_se_id( n ) {} 129 130 // Destructor 131 ~ms_se_exception() {} 132 133 // access methods 134 unsigned int id() const { return m_se_id; } 135 136private: 137 // Data members 138 unsigned int m_se_id; 139}; 140 141//____________________________________________________________________________// 142 143void BOOST_TEST_CALL_DECL ms_se_trans_func( unsigned int id, _EXCEPTION_POINTERS* exps ); 144void BOOST_TEST_CALL_DECL ms_se_forward_func( unsigned int id, _EXCEPTION_POINTERS* exps ); 145static void report_ms_se_error( unsigned int id ); 146 147//____________________________________________________________________________// 148 149// Declarations for unix-style signal handling 150#elif defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) 151 152class unix_signal_exception { 153 typedef execution_exception::error_code error_code_type; 154public: 155 // Constructor 156 unix_signal_exception( execution_exception::error_code ec, const_string em ) 157 : m_error_code( ec ), m_error_message( em ) {} 158 159 // Destructor 160 ~unix_signal_exception() {} 161 162 // access methods 163 error_code_type error_code() const { return m_error_code; } 164 const_string error_message() const { return m_error_message; } 165private: 166 // Data members 167 error_code_type m_error_code; 168 const_string m_error_message; 169}; 170 171#endif 172 173//____________________________________________________________________________// 174 175#if defined(BOOST_MS_CRT_DEBUG_HOOKS) 176 177int BOOST_TEST_CALL_DECL 178assert_reporting_function( int reportType, char* userMessage, int* retVal ) 179{ 180 switch( reportType ) { 181 case _CRT_ASSERT: 182 detail::report_error( execution_exception::user_error, userMessage ); 183 184 return 1; // return value and retVal are not important since we never reach this line 185 case _CRT_ERROR: 186 detail::report_error( execution_exception::system_error, userMessage ); 187 188 return 1; // return value and retVal are not important since we never reach this line 189 default: 190 return 0; // use usual reporting method 191 } 192} 193 194#endif 195 196} // namespace detail 197 198// ************************************************************************** // 199// ************** execution_monitor ************** // 200// ************************************************************************** // 201 202int 203execution_monitor::execute( unit_test::callback0<int> const& F, bool catch_system_errors, int timeout ) 204{ 205 using unit_test::const_string; 206 207# ifdef BOOST_TEST_DEBUGGER_CHECK 208 if( IsDebuggerPresent() ) 209 catch_system_errors = false; 210#endif 211 212#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) && !defined(__BORLANDC__) 213 if( catch_system_errors ) 214 _set_se_translator( detail::ms_se_trans_func ); 215 else 216 _set_se_translator( detail::ms_se_forward_func ); 217#endif 218 219#ifdef BOOST_MS_CRT_DEBUG_HOOKS 220 if( catch_system_errors ) 221 _CrtSetReportHook( &detail::assert_reporting_function ); 222#endif 223 224 try { 225 return catch_signals( F, catch_system_errors, timeout ); 226 } 227 228 // Catch-clause reference arguments are a bit different from function 229 // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't 230 // required. Programmers ask for const anyhow, so we supply it. That's 231 // easier than answering questions about non-const usage. 232 233 catch( execution_aborted const& ) 234 { return 0; } 235 catch( char const* ex ) 236 { detail::report_error( execution_exception::cpp_exception_error, "C string: ", ex ); } 237 catch( std::string const& ex ) 238 { detail::report_error( execution_exception::cpp_exception_error, "std::string: ", ex.c_str() ); } 239 240 // std:: exceptions 241 242 catch( std::bad_alloc const& ex ) 243 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_alloc: ", ex.what() ); } 244 245#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) 246 catch( std::bad_cast const& ex ) 247 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_cast" ); } 248 catch( std::bad_typeid const& ex ) 249 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_typeid" ); } 250#else 251 catch( std::bad_cast const& ex ) 252 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_cast: ", ex.what() ); } 253 catch( std::bad_typeid const& ex ) 254 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_typeid: ", ex.what() ); } 255#endif 256 257 catch( std::bad_exception const& ex ) 258 { detail::report_error( execution_exception::cpp_exception_error, "std::bad_exception: ", ex.what() ); } 259 catch( std::domain_error const& ex ) 260 { detail::report_error( execution_exception::cpp_exception_error, "std::domain_error: ", ex.what() ); } 261 catch( std::invalid_argument const& ex ) 262 { detail::report_error( execution_exception::cpp_exception_error, "std::invalid_argument: ", ex.what() ); } 263 catch( std::length_error const& ex ) 264 { detail::report_error( execution_exception::cpp_exception_error, "std::length_error: ", ex.what() ); } 265 catch( std::out_of_range const& ex ) 266 { detail::report_error( execution_exception::cpp_exception_error, "std::out_of_range: ", ex.what() ); } 267 catch( std::range_error const& ex ) 268 { detail::report_error( execution_exception::cpp_exception_error, "std::range_error: ", ex.what() ); } 269 catch( std::overflow_error const& ex ) 270 { detail::report_error( execution_exception::cpp_exception_error, "std::overflow_error: ", ex.what() ); } 271 catch( std::underflow_error const& ex ) 272 { detail::report_error( execution_exception::cpp_exception_error, "std::underflow_error: ", ex.what() ); } 273 catch( std::logic_error const& ex ) 274 { detail::report_error( execution_exception::cpp_exception_error, "std::logic_error: ", ex.what() ); } 275 catch( std::runtime_error const& ex ) 276 { detail::report_error( execution_exception::cpp_exception_error, "std::runtime_error: ", ex.what() ); } 277 catch( std::exception const& ex ) 278 { detail::report_error( execution_exception::cpp_exception_error, "std::exception: ", ex.what() ); } 279 280#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) 281 catch( detail::ms_se_exception const& ex ) 282 { detail::report_ms_se_error( ex.id() ); } 283#elif defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) 284 catch( detail::unix_signal_exception const& ex ) 285 { detail::report_error( ex.error_code(), ex.error_message() ); } 286#endif // BOOST_SIGACTION_BASED_SIGNAL_HANDLING 287 288 catch( execution_exception const& ) { throw; } 289 290 catch( ... ) 291 { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); } 292 293 return 0; // never reached; supplied to quiet compiler warnings 294} // execute 295 296//____________________________________________________________________________// 297 298#if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) 299 300// ************************************************************************** // 301// ************** boost::detail::signal_handler ************** // 302// ************************************************************************** // 303 304namespace detail { 305 306class signal_handler { 307public: 308 // Constructor 309 explicit signal_handler( bool catch_system_errors, int timeout ); 310 311 // Destructor 312 ~signal_handler(); 313 314 // access methods 315 static sigjmp_buf& jump_buffer() 316 { 317 assert( !!s_active_handler ); 318 319 return s_active_handler->m_sigjmp_buf; 320 } 321 322private: 323 // Data members 324 struct sigaction m_same_action_for_all_signals; 325 struct sigaction m_old_SIGFPE_action; 326 struct sigaction m_old_SIGTRAP_action; 327 struct sigaction m_old_SIGSEGV_action; 328 struct sigaction m_old_SIGBUS_action; 329 struct sigaction m_old_SIGABRT_action; 330 struct sigaction m_old_SIGALRM_action; 331 332 sigjmp_buf m_sigjmp_buf; 333 334 signal_handler* m_prev_handler; 335 static signal_handler* s_active_handler; 336 337 bool m_catch_system_errors; 338 bool m_set_timeout; 339}; 340 341signal_handler* signal_handler::s_active_handler = NULL; //!! need to be placed in thread specific storage 342 343//____________________________________________________________________________// 344 345extern "C" { 346 347static void execution_monitor_signal_handler( int sig ) 348{ 349 siglongjmp( signal_handler::jump_buffer(), sig ); 350} 351 352} 353 354//____________________________________________________________________________// 355 356signal_handler::signal_handler( bool catch_system_errors, int timeout ) 357: m_prev_handler( s_active_handler ) 358, m_catch_system_errors( catch_system_errors ) 359, m_set_timeout( timeout > 0 ) 360{ 361 s_active_handler = this; 362 363 if( m_catch_system_errors || m_set_timeout ) { 364 m_same_action_for_all_signals.sa_flags = 0; 365 m_same_action_for_all_signals.sa_handler = &execution_monitor_signal_handler; 366 sigemptyset( &m_same_action_for_all_signals.sa_mask ); 367 } 368 369 if( m_catch_system_errors ) { 370 sigaction( SIGFPE , &m_same_action_for_all_signals, &m_old_SIGFPE_action ); 371 sigaction( SIGTRAP, &m_same_action_for_all_signals, &m_old_SIGTRAP_action ); 372 sigaction( SIGSEGV, &m_same_action_for_all_signals, &m_old_SIGSEGV_action ); 373 sigaction( SIGBUS , &m_same_action_for_all_signals, &m_old_SIGBUS_action ); 374 sigaction( SIGABRT, &m_same_action_for_all_signals, &m_old_SIGABRT_action ); 375 } 376 377 if( m_set_timeout ) { 378 sigaction( SIGALRM , &m_same_action_for_all_signals, &m_old_SIGALRM_action ); 379 alarm( timeout ); 380 } 381} 382 383//____________________________________________________________________________// 384 385signal_handler::~signal_handler() 386{ 387 typedef struct sigaction* sigaction_ptr; 388 389 assert( s_active_handler == this ); 390 391 if( m_set_timeout ) { 392 alarm( 0 ); 393 sigaction( SIGALRM, &m_old_SIGALRM_action, sigaction_ptr() ); 394 } 395 396 if( m_catch_system_errors ) { 397 sigaction( SIGFPE , &m_old_SIGFPE_action , sigaction_ptr() ); 398 sigaction( SIGTRAP, &m_old_SIGTRAP_action, sigaction_ptr() ); 399 sigaction( SIGSEGV, &m_old_SIGSEGV_action, sigaction_ptr() ); 400 sigaction( SIGBUS , &m_old_SIGBUS_action , sigaction_ptr() ); 401 sigaction( SIGABRT, &m_old_SIGABRT_action, sigaction_ptr() ); 402 } 403 404 s_active_handler = m_prev_handler; 405} 406 407//____________________________________________________________________________// 408 409} // namespace detail 410 411// ************************************************************************** // 412// ************** execution_monitor::catch_signals ************** // 413// ************************************************************************** // 414 415int 416execution_monitor::catch_signals( unit_test::callback0<int> const& F, bool catch_system_errors, int timeout ) 417{ 418 using namespace detail; 419 typedef execution_exception::error_code ec_type; 420 421 signal_handler local_signal_handler( catch_system_errors, timeout ); 422 int result = 0; 423 ec_type ec = execution_exception::no_error; 424 const_string em; 425 426 volatile int sigtype = sigsetjmp( signal_handler::jump_buffer(), 1 ); 427 if( sigtype == 0 ) { 428 result = m_custom_translators ? (*m_custom_translators)( F ) : F(); 429 } 430 else { 431 switch(sigtype) { 432 case SIGALRM: 433 ec = execution_exception::timeout_error; 434 em = BOOST_TEST_L( "signal: SIGALRM (timeout while executing function)" ); 435 break; 436 case SIGTRAP: 437 ec = execution_exception::system_error; 438 em = BOOST_TEST_L( "signal: SIGTRAP (perhaps integer divide by zero)" ); 439 break; 440 case SIGFPE: 441 ec = execution_exception::system_error; 442 em = BOOST_TEST_L( "signal: SIGFPE (arithmetic exception)" ); 443 break; 444 case SIGABRT: 445 ec = execution_exception::system_error; 446 em = BOOST_TEST_L( "signal: SIGABRT (application abort requested)" ); 447 break; 448 case SIGSEGV: 449 case SIGBUS: 450 ec = execution_exception::system_fatal_error; 451 em = BOOST_TEST_L( "signal: memory access violation" ); 452 break; 453 default: 454 ec = execution_exception::system_error; 455 em = BOOST_TEST_L( "signal: unrecognized signal" ); 456 } 457 } 458 459 if( ec != execution_exception::no_error ) 460 throw unix_signal_exception( ec, em ); 461 462 return result; 463} // unix catch_signals 464 465//____________________________________________________________________________// 466 467#elif (defined(__BORLANDC__) && defined(_Windows) && !defined(BOOST_DISABLE_WIN32)) 468 469// this works for Borland but not other Win32 compilers (which trap too many cases) 470int 471execution_monitor::catch_signals( unit_test::callback0<int> const& F, bool catch_system_errors, int ) 472{ 473 int result; 474 475 if( catch_system_errors ) { 476 __try { result = m_custom_translators ? (*m_custom_translators)( F ) : F(); } 477 478 __except (1) { 479 throw detail::ms_se_exception( GetExceptionCode() ); 480 } 481 } 482 else 483 result = m_custom_translators ? (*m_custom_translators)( F ) : F(); 484 485 return result; 486} 487 488#else // default signal handler 489 490int 491execution_monitor::catch_signals( unit_test::callback0<int> const& F, bool, int ) 492{ 493 return m_custom_translators ? (*m_custom_translators)( F ) : F(); 494} 495 496#endif // choose signal handler 497 498// ************************************************************************** // 499// ************** Microsoft structured exception handling ************** // 500// ************************************************************************** // 501 502#if defined(BOOST_MS_STRUCTURED_EXCEPTION_HANDLING) 503 504namespace detail { 505 506void BOOST_TEST_CALL_DECL 507ms_se_trans_func( unsigned int id, _EXCEPTION_POINTERS* /* exps */ ) 508{ 509 throw ms_se_exception( id ); 510} 511 512//____________________________________________________________________________// 513 514void BOOST_TEST_CALL_DECL 515ms_se_forward_func( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) 516{ 517 throw; 518} 519 520//____________________________________________________________________________// 521 522void 523report_ms_se_error( unsigned int id ) 524{ 525 switch( id ) { 526 // cases classified as fatal_system_error 527 case EXCEPTION_ACCESS_VIOLATION: 528 detail::report_error( execution_exception::system_fatal_error, "memory access violation" ); 529 break; 530 531 case EXCEPTION_ILLEGAL_INSTRUCTION: 532 detail::report_error( execution_exception::system_fatal_error, "illegal instruction" ); 533 break; 534 535 case EXCEPTION_PRIV_INSTRUCTION: 536 detail::report_error( execution_exception::system_fatal_error, "privileged instruction" ); 537 break; 538 539 case EXCEPTION_IN_PAGE_ERROR: 540 detail::report_error( execution_exception::system_fatal_error, "memory page error" ); 541 break; 542 543 case EXCEPTION_STACK_OVERFLOW: 544 detail::report_error( execution_exception::system_fatal_error, "stack overflow" ); 545 break; 546 547 // cases classified as (non-fatal) system_trap 548 case EXCEPTION_DATATYPE_MISALIGNMENT: 549 detail::report_error( execution_exception::system_error, "data misalignment" ); 550 break; 551 552 case EXCEPTION_INT_DIVIDE_BY_ZERO: 553 detail::report_error( execution_exception::system_error, "integer divide by zero" ); 554 break; 555 556 case EXCEPTION_INT_OVERFLOW: 557 detail::report_error( execution_exception::system_error, "integer overflow" ); 558 break; 559 560 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 561 detail::report_error( execution_exception::system_error, "array bounds exceeded" ); 562 break; 563 564 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 565 detail::report_error( execution_exception::system_error, "floating point divide by zero" ); 566 break; 567 568 case EXCEPTION_FLT_STACK_CHECK: 569 detail::report_error( execution_exception::system_error, "floating point stack check" ); 570 break; 571 572 case EXCEPTION_FLT_DENORMAL_OPERAND: 573 case EXCEPTION_FLT_INEXACT_RESULT: 574 case EXCEPTION_FLT_INVALID_OPERATION: 575 case EXCEPTION_FLT_OVERFLOW: 576 case EXCEPTION_FLT_UNDERFLOW: 577 detail::report_error( execution_exception::system_error, "floating point error" ); 578 break; 579 580 default: 581 detail::report_error( execution_exception::system_error, "unrecognized exception or signal" ); 582 break; 583 } // switch 584} // report_ms_se_error 585 586//____________________________________________________________________________// 587 588} // namespace detail 589 590#endif // Microsoft structured exception handling 591 592// ************************************************************************** // 593// ************** report_error ************** // 594// ************************************************************************** // 595 596namespace detail { 597 598static void report_error( execution_exception::error_code ec, const_string msg1, const_string msg2 ) 599{ 600 static char buf[REPORT_ERROR_BUFFER_SIZE]; 601 602 buf[0] = '\0'; 603 604 std::strncat( buf, msg1.begin(), sizeof(buf)-1 ); 605 std::strncat( buf, msg2.begin(), sizeof(buf) - msg1.size() - 1 ); 606 607 throw execution_exception( ec, buf ); 608} 609 610//____________________________________________________________________________// 611 612} // namespace detail 613 614// ************************************************************************** // 615// ************** detect_memory_leak ************** // 616// ************************************************************************** // 617 618void 619detect_memory_leak( long mem_leak_alloc_num ) 620{ 621 unit_test::ut_detail::ignore_unused_variable_warning( mem_leak_alloc_num ); 622 623#ifdef BOOST_MS_CRT_DEBUG_HOOKS 624 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); 625 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 626 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); 627 628 if( mem_leak_alloc_num > 1 ) 629 _CrtSetBreakAlloc( mem_leak_alloc_num ); 630#endif // BOOST_MS_CRT_DEBUG_HOOKS 631} 632 633} // namespace boost 634 635//____________________________________________________________________________// 636 637#include <boost/test/detail/enable_warnings.hpp> 638 639// *************************************************************************** 640// Revision History : 641// 642// $Log: execution_monitor.ipp,v $ 643// Revision 1.1.1.1 2006/03/20 20:15:27 ewalkup 644// boost libraries 645// 646// Revision 1.9 2005/04/30 17:07:22 rogeeff 647// ignore_warning included 648// 649// Revision 1.8 2005/04/30 16:46:50 rogeeff 650// warning suppressed 651// 652// Revision 1.7 2005/04/13 05:32:03 rogeeff 653// typo fix 654// 655// Revision 1.6 2005/04/05 06:11:37 rogeeff 656// memory leak allocation point detection\nextra help with _WIN32_WINNT 657// 658// Revision 1.5 2005/02/20 08:27:07 rogeeff 659// This a major update for Boost.Test framework. See release docs for complete list of fixes/updates 660// 661// Revision 1.4 2005/02/01 06:40:07 rogeeff 662// copyright update 663// old log entries removed 664// minor stilistic changes 665// depricated tools removed 666// 667// Revision 1.3 2005/01/31 07:50:06 rogeeff 668// cdecl portability fix 669// 670// Revision 1.2 2005/01/31 05:58:03 rogeeff 671// detect_memory_leak feature added 672// 673// Revision 1.1 2005/01/22 19:22:12 rogeeff 674// implementation moved into headers section to eliminate dependency of included/minimal component on src directory 675// 676// Revision 1.36 2005/01/21 07:21:38 rogeeff 677// detect presence of debugger under VC and automatically prevent catching system errors 678// 679// *************************************************************************** 680 681#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER 682