source: NonGTP/Boost/boost/test/impl/execution_monitor.ipp @ 857

Revision 857, 24.2 KB checked in by igarcia, 19 years ago (diff)
Line 
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.9 $
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.9  2005/04/30 17:07:22  rogeeff
644//  ignore_warning included
645//
646//  Revision 1.8  2005/04/30 16:46:50  rogeeff
647//  warning suppressed
648//
649//  Revision 1.7  2005/04/13 05:32:03  rogeeff
650//  typo fix
651//
652//  Revision 1.6  2005/04/05 06:11:37  rogeeff
653//  memory leak allocation point detection\nextra help with _WIN32_WINNT
654//
655//  Revision 1.5  2005/02/20 08:27:07  rogeeff
656//  This a major update for Boost.Test framework. See release docs for complete list of fixes/updates
657//
658//  Revision 1.4  2005/02/01 06:40:07  rogeeff
659//  copyright update
660//  old log entries removed
661//  minor stilistic changes
662//  depricated tools removed
663//
664//  Revision 1.3  2005/01/31 07:50:06  rogeeff
665//  cdecl portability fix
666//
667//  Revision 1.2  2005/01/31 05:58:03  rogeeff
668//  detect_memory_leak feature added
669//
670//  Revision 1.1  2005/01/22 19:22:12  rogeeff
671//  implementation moved into headers section to eliminate dependency of included/minimal component on src directory
672//
673//  Revision 1.36  2005/01/21 07:21:38  rogeeff
674//  detect presence of debugger under VC and automatically prevent catching system errors
675//
676// ***************************************************************************
677
678#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
Note: See TracBrowser for help on using the repository browser.