1//  (C) Copyright Gennadiy Rozental 2001.
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
10///  Provides execution monitor implementation for all supported
11///  configurations, including Microsoft structured exception based, unix signals
12///  based and special workarounds for borland
13///
14///  Note that when testing requirements or user wishes preclude use of this
15///  file as a separate compilation unit, it may be included as a header file.
16///
17///  Header dependencies are deliberately restricted to reduce coupling to other
18///  boost libraries.
19// ***************************************************************************
20
21#ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
22#define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
23
24// Boost.Test
25#include <boost/test/detail/config.hpp>
26#include <boost/test/detail/workaround.hpp>
27#include <boost/test/detail/throw_exception.hpp>
28#include <boost/test/execution_monitor.hpp>
29#include <boost/test/debug.hpp>
30
31// Boost
32#include <boost/cstdlib.hpp>    // for exit codes
33#include <boost/config.hpp>     // for workarounds
34#include <boost/core/ignore_unused.hpp> // for ignore_unused
35#ifndef BOOST_NO_EXCEPTIONS
36#include <boost/exception/get_error_info.hpp> // for get_error_info
37#include <boost/exception/current_exception_cast.hpp> // for current_exception_cast
38#endif
39
40// STL
41#include <string>               // for std::string
42#include <new>                  // for std::bad_alloc
43#include <typeinfo>             // for std::bad_cast, std::bad_typeid
44#include <exception>            // for std::exception, std::bad_exception
45#include <stdexcept>            // for std exception hierarchy
46#include <cstring>              // for C string API
47#include <cassert>              // for assert
48#include <cstddef>              // for NULL
49#include <cstdio>               // for vsnprintf
50#include <cstdarg>              // for varargs
51
52#include <iostream>              // for varargs
53
54#ifdef BOOST_NO_STDC_NAMESPACE
55namespace std { using ::strerror; using ::strlen; using ::strncat; }
56#endif
57
58// to use vsnprintf
59#if defined(__SUNPRO_CC) || defined(__SunOS)
60#  include <stdio.h>
61#  include <stdarg.h>
62using std::va_list;
63#endif
64
65// to use vsnprintf
66#if defined(__QNXNTO__)
67#  include <stdio.h>
68using std::va_list;
69#endif
70
71#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
72#  include <windows.h>
73
74#  if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE))
75#    include <eh.h>
76#  endif
77
78#  if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 || defined(__MWERKS__)
79#    include <stdint.h>
80#  endif
81
82#  if defined(__BORLANDC__) && __BORLANDC__ < 0x560
83    typedef unsigned uintptr_t;
84#  endif
85
86#  if defined(UNDER_CE) && BOOST_WORKAROUND(_MSC_VER,  < 1500 )
87   typedef void* uintptr_t;
88#  elif defined(UNDER_CE)
89#  include <crtdefs.h>
90#  endif
91
92#  if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE)
93#    include <crtdbg.h>
94#    define BOOST_TEST_CRT_HOOK_TYPE    _CRT_REPORT_HOOK
95#    define BOOST_TEST_CRT_ASSERT       _CRT_ASSERT
96#    define BOOST_TEST_CRT_ERROR        _CRT_ERROR
97#    define BOOST_TEST_CRT_SET_HOOK(H)  _CrtSetReportHook(H)
98#  else
99#    define BOOST_TEST_CRT_HOOK_TYPE    void*
100#    define BOOST_TEST_CRT_ASSERT       2
101#    define BOOST_TEST_CRT_ERROR        1
102#    define BOOST_TEST_CRT_SET_HOOK(H)  (void*)(H)
103#  endif
104
105#  if (!BOOST_WORKAROUND(_MSC_VER,  >= 1400 ) && \
106      !defined(BOOST_COMO)) || defined(UNDER_CE)
107
108typedef void* _invalid_parameter_handler;
109
110inline _invalid_parameter_handler
111_set_invalid_parameter_handler( _invalid_parameter_handler arg )
112{
113    return arg;
114}
115
116#  endif
117
118#  if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE)
119
120namespace { void _set_se_translator( void* ) {} }
121
122#  endif
123
124#elif defined(BOOST_HAS_SIGACTION)
125
126#  define BOOST_SIGACTION_BASED_SIGNAL_HANDLING
127
128#  include <unistd.h>
129#  include <signal.h>
130#  include <setjmp.h>
131
132#  if defined(__FreeBSD__)
133
134#    include <osreldate.h>
135
136#    ifndef SIGPOLL
137#      define SIGPOLL SIGIO
138#    endif
139
140#    if (__FreeBSD_version < 70100)
141
142#      define ILL_ILLADR 0 // ILL_RESAD_FAULT
143#      define ILL_PRVOPC ILL_PRIVIN_FAULT
144#      define ILL_ILLOPN 2 // ILL_RESOP_FAULT
145#      define ILL_COPROC ILL_FPOP_FAULT
146
147#      define BOOST_TEST_LIMITED_SIGNAL_DETAILS
148
149#    endif
150#  endif
151
152#  if defined(__ANDROID__)
153#    include <android/api-level.h>
154#  endif
155
156// documentation of BOOST_TEST_DISABLE_ALT_STACK in execution_monitor.hpp
157#  if !defined(__CYGWIN__) && !defined(__QNXNTO__) && !defined(__bgq__) && \
158   (!defined(__ANDROID__) || __ANDROID_API__ >= 8) && \
159   !defined(BOOST_TEST_DISABLE_ALT_STACK)
160#    define BOOST_TEST_USE_ALT_STACK
161#  endif
162
163#  if defined(SIGPOLL) && !defined(__CYGWIN__)                              && \
164      !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))  && \
165      !defined(__NetBSD__)                                                  && \
166      !defined(__QNXNTO__)
167#    define BOOST_TEST_CATCH_SIGPOLL
168#  endif
169
170#  ifdef BOOST_TEST_USE_ALT_STACK
171#    define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ
172#  endif
173
174
175#else
176
177#  define BOOST_NO_SIGNAL_HANDLING
178
179#endif
180
181#ifndef UNDER_CE
182#include <errno.h>
183#endif
184
185#if !defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI)
186#  include <boost/core/demangle.hpp>
187#endif
188
189#include <boost/test/detail/suppress_warnings.hpp>
190
191//____________________________________________________________________________//
192
193namespace boost {
194
195// ************************************************************************** //
196// **************                 throw_exception              ************** //
197// ************************************************************************** //
198
199#ifdef BOOST_NO_EXCEPTIONS
200void throw_exception( std::exception const & e ) { abort(); }
201#endif
202
203// ************************************************************************** //
204// **************                  report_error                ************** //
205// ************************************************************************** //
206
207namespace detail {
208
209#ifdef __BORLANDC__
210#  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) )
211#elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \
212      BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \
213      defined(UNDER_CE)
214#  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) )
215#else
216#  define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) )
217#endif
218
219#ifndef BOOST_NO_EXCEPTIONS
220
221template <typename ErrorInfo>
222typename ErrorInfo::value_type
223extract( boost::exception const* ex )
224{
225    if( !ex )
226        return 0;
227
228    typename ErrorInfo::value_type const * val = boost::get_error_info<ErrorInfo>( *ex );
229
230    return val ? *val : 0;
231}
232
233//____________________________________________________________________________//
234
235static void
236report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, va_list* args )
237{
238    static const int REPORT_ERROR_BUFFER_SIZE = 4096;
239    static char buf[REPORT_ERROR_BUFFER_SIZE];
240
241    BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args );
242    buf[sizeof(buf)-1] = 0;
243
244    va_end( *args );
245
246    BOOST_TEST_I_THROW(execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ),
247                                                                                    (size_t)extract<throw_line>( be ),
248                                                                                    extract<throw_function>( be ) ) ));
249}
250
251//____________________________________________________________________________//
252
253static void
254report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... )
255{
256    va_list args;
257    va_start( args, format );
258
259    report_error( ec, be, format, &args );
260}
261
262#endif
263
264//____________________________________________________________________________//
265
266static void
267report_error( execution_exception::error_code ec, char const* format, ... )
268{
269    va_list args;
270    va_start( args, format );
271
272    report_error( ec, 0, format, &args );
273}
274
275//____________________________________________________________________________//
276
277template<typename Tr,typename Functor>
278inline int
279do_invoke( Tr const& tr, Functor const& F )
280{
281    return tr ? (*tr)( F ) : F();
282}
283
284//____________________________________________________________________________//
285
286struct fpe_except_guard {
287    explicit fpe_except_guard( unsigned detect_fpe )
288    : m_detect_fpe( detect_fpe )
289    {
290        // prepare fp exceptions control
291        m_previously_enabled = fpe::disable( fpe::BOOST_FPE_ALL );
292        if( m_previously_enabled != fpe::BOOST_FPE_INV && detect_fpe != fpe::BOOST_FPE_OFF )
293            fpe::enable( detect_fpe );
294    }
295    ~fpe_except_guard()
296    {
297        if( m_detect_fpe != fpe::BOOST_FPE_OFF )
298            fpe::disable( m_detect_fpe );
299        if( m_previously_enabled != fpe::BOOST_FPE_INV )
300            fpe::enable( m_previously_enabled );
301    }
302
303    unsigned m_detect_fpe;
304    unsigned m_previously_enabled;
305};
306
307
308// ************************************************************************** //
309// **************                  typeid_name                 ************** //
310// ************************************************************************** //
311
312#if !defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI)
313template<typename T>
314std::string
315typeid_name( T const& t )
316{
317    return boost::core::demangle(typeid(t).name());
318}
319#endif
320
321} // namespace detail
322
323#if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING)
324
325// ************************************************************************** //
326// **************       Sigaction based signal handling        ************** //
327// ************************************************************************** //
328
329namespace detail {
330
331// ************************************************************************** //
332// **************    boost::detail::system_signal_exception    ************** //
333// ************************************************************************** //
334
335class system_signal_exception {
336public:
337    // Constructor
338    system_signal_exception()
339    : m_sig_info( 0 )
340    , m_context( 0 )
341    {}
342
343    // Access methods
344    void        operator()( siginfo_t* i, void* c )
345    {
346        m_sig_info  = i;
347        m_context   = c;
348    }
349    void        report() const;
350
351private:
352    // Data members
353    siginfo_t*  m_sig_info; // system signal detailed info
354    void*       m_context;  // signal context
355};
356
357//____________________________________________________________________________//
358
359void
360system_signal_exception::report() const
361{
362    if( !m_sig_info )
363        return; // no error actually occur?
364
365    switch( m_sig_info->si_code ) {
366    case SI_USER:
367        report_error( execution_exception::system_error,
368                      "signal: generated by kill() (or family); uid=%d; pid=%d",
369                      (int)m_sig_info->si_uid, (int)m_sig_info->si_pid );
370        break;
371    case SI_QUEUE:
372        report_error( execution_exception::system_error,
373                      "signal: sent by sigqueue()" );
374        break;
375    case SI_TIMER:
376        report_error( execution_exception::system_error,
377                      "signal: the expiration of a timer set by timer_settimer()" );
378        break;
379    case SI_ASYNCIO:
380        report_error( execution_exception::system_error,
381                      "signal: generated by the completion of an asynchronous I/O request" );
382        break;
383    case SI_MESGQ:
384        report_error( execution_exception::system_error,
385                      "signal: generated by the the arrival of a message on an empty message queue" );
386        break;
387    default:
388        break;
389    }
390
391    switch( m_sig_info->si_signo ) {
392    case SIGILL:
393        switch( m_sig_info->si_code ) {
394#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
395        case ILL_ILLOPC:
396            report_error( execution_exception::system_fatal_error,
397                          "signal: illegal opcode; address of failing instruction: 0x%08lx",
398                          m_sig_info->si_addr );
399            break;
400        case ILL_ILLTRP:
401            report_error( execution_exception::system_fatal_error,
402                          "signal: illegal trap; address of failing instruction: 0x%08lx",
403                          m_sig_info->si_addr );
404            break;
405        case ILL_PRVREG:
406            report_error( execution_exception::system_fatal_error,
407                          "signal: privileged register; address of failing instruction: 0x%08lx",
408                          m_sig_info->si_addr );
409            break;
410        case ILL_BADSTK:
411            report_error( execution_exception::system_fatal_error,
412                          "signal: internal stack error; address of failing instruction: 0x%08lx",
413                          m_sig_info->si_addr );
414            break;
415#endif
416        case ILL_ILLOPN:
417            report_error( execution_exception::system_fatal_error,
418                          "signal: illegal operand; address of failing instruction: 0x%08lx",
419                          m_sig_info->si_addr );
420            break;
421        case ILL_ILLADR:
422            report_error( execution_exception::system_fatal_error,
423                          "signal: illegal addressing mode; address of failing instruction: 0x%08lx",
424                          m_sig_info->si_addr );
425            break;
426        case ILL_PRVOPC:
427            report_error( execution_exception::system_fatal_error,
428                          "signal: privileged opcode; address of failing instruction: 0x%08lx",
429                          m_sig_info->si_addr );
430            break;
431        case ILL_COPROC:
432            report_error( execution_exception::system_fatal_error,
433                          "signal: co-processor error; address of failing instruction: 0x%08lx",
434                          m_sig_info->si_addr );
435            break;
436        default:
437            report_error( execution_exception::system_fatal_error,
438                          "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)",
439                          m_sig_info->si_addr, m_sig_info->si_code );
440            break;
441        }
442        break;
443
444    case SIGFPE:
445        switch( m_sig_info->si_code ) {
446        case FPE_INTDIV:
447            report_error( execution_exception::system_error,
448                          "signal: integer divide by zero; address of failing instruction: 0x%08lx",
449                          m_sig_info->si_addr );
450            break;
451        case FPE_INTOVF:
452            report_error( execution_exception::system_error,
453                          "signal: integer overflow; address of failing instruction: 0x%08lx",
454                          m_sig_info->si_addr );
455            break;
456        case FPE_FLTDIV:
457            report_error( execution_exception::system_error,
458                          "signal: floating point divide by zero; address of failing instruction: 0x%08lx",
459                          m_sig_info->si_addr );
460            break;
461        case FPE_FLTOVF:
462            report_error( execution_exception::system_error,
463                          "signal: floating point overflow; address of failing instruction: 0x%08lx",
464                          m_sig_info->si_addr );
465            break;
466        case FPE_FLTUND:
467            report_error( execution_exception::system_error,
468                          "signal: floating point underflow; address of failing instruction: 0x%08lx",
469                          m_sig_info->si_addr );
470            break;
471        case FPE_FLTRES:
472            report_error( execution_exception::system_error,
473                          "signal: floating point inexact result; address of failing instruction: 0x%08lx",
474                          m_sig_info->si_addr );
475            break;
476        case FPE_FLTINV:
477            report_error( execution_exception::system_error,
478                          "signal: invalid floating point operation; address of failing instruction: 0x%08lx",
479                          m_sig_info->si_addr );
480            break;
481        case FPE_FLTSUB:
482            report_error( execution_exception::system_error,
483                          "signal: subscript out of range; address of failing instruction: 0x%08lx",
484                          m_sig_info->si_addr );
485            break;
486        default:
487            report_error( execution_exception::system_error,
488                          "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)",
489                          m_sig_info->si_addr, m_sig_info->si_code );
490            break;
491        }
492        break;
493
494    case SIGSEGV:
495        switch( m_sig_info->si_code ) {
496#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
497        case SEGV_MAPERR:
498            report_error( execution_exception::system_fatal_error,
499                          "memory access violation at address: 0x%08lx: no mapping at fault address",
500                          m_sig_info->si_addr );
501            break;
502        case SEGV_ACCERR:
503            report_error( execution_exception::system_fatal_error,
504                          "memory access violation at address: 0x%08lx: invalid permissions",
505                          m_sig_info->si_addr );
506            break;
507#endif
508        default:
509            report_error( execution_exception::system_fatal_error,
510                          "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)",
511                          m_sig_info->si_addr, m_sig_info->si_code );
512            break;
513        }
514        break;
515
516    case SIGBUS:
517        switch( m_sig_info->si_code ) {
518#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
519        case BUS_ADRALN:
520            report_error( execution_exception::system_fatal_error,
521                          "memory access violation at address: 0x%08lx: invalid address alignment",
522                          m_sig_info->si_addr );
523            break;
524        case BUS_ADRERR:
525            report_error( execution_exception::system_fatal_error,
526                          "memory access violation at address: 0x%08lx: non-existent physical address",
527                          m_sig_info->si_addr );
528            break;
529        case BUS_OBJERR:
530            report_error( execution_exception::system_fatal_error,
531                          "memory access violation at address: 0x%08lx: object specific hardware error",
532                          m_sig_info->si_addr );
533            break;
534#endif
535        default:
536            report_error( execution_exception::system_fatal_error,
537                          "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)",
538                          m_sig_info->si_addr, m_sig_info->si_code );
539            break;
540        }
541        break;
542
543#if defined(BOOST_TEST_CATCH_SIGPOLL)
544
545    case SIGPOLL:
546        switch( m_sig_info->si_code ) {
547#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
548        case POLL_IN:
549            report_error( execution_exception::system_error,
550                          "data input available; band event %d",
551                          (int)m_sig_info->si_band );
552            break;
553        case POLL_OUT:
554            report_error( execution_exception::system_error,
555                          "output buffers available; band event %d",
556                          (int)m_sig_info->si_band );
557            break;
558        case POLL_MSG:
559            report_error( execution_exception::system_error,
560                          "input message available; band event %d",
561                          (int)m_sig_info->si_band );
562            break;
563        case POLL_ERR:
564            report_error( execution_exception::system_error,
565                          "i/o error; band event %d",
566                          (int)m_sig_info->si_band );
567            break;
568        case POLL_PRI:
569            report_error( execution_exception::system_error,
570                          "high priority input available; band event %d",
571                          (int)m_sig_info->si_band );
572            break;
573#if defined(POLL_ERR) && defined(POLL_HUP) && (POLL_ERR - POLL_HUP)
574        case POLL_HUP:
575            report_error( execution_exception::system_error,
576                          "device disconnected; band event %d",
577                          (int)m_sig_info->si_band );
578            break;
579#endif
580#endif
581        default:
582            report_error( execution_exception::system_error,
583                          "signal: SIGPOLL, si_code: %d (asynchronous I/O event occurred; band event %d)",
584                          (int)m_sig_info->si_band, m_sig_info->si_code );
585            break;
586        }
587        break;
588
589#endif
590
591    case SIGABRT:
592        report_error( execution_exception::system_error,
593                      "signal: SIGABRT (application abort requested)" );
594        break;
595
596    case SIGALRM:
597        report_error( execution_exception::timeout_error,
598                      "signal: SIGALRM (timeout while executing function)" );
599        break;
600
601    default:
602        report_error( execution_exception::system_error,
603                      "unrecognized signal %d", m_sig_info->si_signo );
604    }
605}
606
607//____________________________________________________________________________//
608
609// ************************************************************************** //
610// **************         boost::detail::signal_action         ************** //
611// ************************************************************************** //
612
613// Forward declaration
614extern "C" {
615static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context );
616static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context );
617}
618
619class signal_action {
620    typedef struct sigaction* sigaction_ptr;
621public:
622    //Constructor
623    signal_action();
624    signal_action( int sig, bool install, bool attach_dbg, char* alt_stack );
625    ~signal_action();
626
627private:
628    // Data members
629    int                 m_sig;
630    bool                m_installed;
631    struct sigaction    m_new_action;
632    struct sigaction    m_old_action;
633};
634
635//____________________________________________________________________________//
636
637signal_action::signal_action()
638: m_installed( false )
639{}
640
641//____________________________________________________________________________//
642
643signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_stack )
644: m_sig( sig )
645, m_installed( install )
646{
647    if( !install )
648        return;
649
650    std::memset( &m_new_action, 0, sizeof(struct sigaction) );
651
652    BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig , sigaction_ptr(), &m_new_action ) != -1 );
653
654    if( m_new_action.sa_sigaction || m_new_action.sa_handler ) {
655        m_installed = false;
656        return;
657    }
658
659    m_new_action.sa_flags     |= SA_SIGINFO;
660    m_new_action.sa_sigaction  = attach_dbg ? &boost_execution_monitor_attaching_signal_handler
661                                            : &boost_execution_monitor_jumping_signal_handler;
662    BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 );
663
664#ifdef BOOST_TEST_USE_ALT_STACK
665    if( alt_stack )
666        m_new_action.sa_flags |= SA_ONSTACK;
667#endif
668
669    BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig, &m_new_action, &m_old_action ) != -1 );
670}
671
672//____________________________________________________________________________//
673
674signal_action::~signal_action()
675{
676    if( m_installed )
677        ::sigaction( m_sig, &m_old_action , sigaction_ptr() );
678}
679
680//____________________________________________________________________________//
681
682// ************************************************************************** //
683// **************        boost::detail::signal_handler         ************** //
684// ************************************************************************** //
685
686class signal_handler {
687public:
688    // Constructor
689    explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack );
690
691    // Destructor
692    ~signal_handler();
693
694    // access methods
695    static sigjmp_buf&      jump_buffer()
696    {
697        assert( !!s_active_handler );
698
699        return s_active_handler->m_sigjmp_buf;
700    }
701
702    static system_signal_exception&  sys_sig()
703    {
704        assert( !!s_active_handler );
705
706        return s_active_handler->m_sys_sig;
707    }
708
709private:
710    // Data members
711    signal_handler*         m_prev_handler;
712    unsigned                m_timeout;
713
714    // Note: We intentionality do not catch SIGCHLD. Users have to deal with it themselves
715    signal_action           m_ILL_action;
716    signal_action           m_FPE_action;
717    signal_action           m_SEGV_action;
718    signal_action           m_BUS_action;
719    signal_action           m_CHLD_action;
720    signal_action           m_POLL_action;
721    signal_action           m_ABRT_action;
722    signal_action           m_ALRM_action;
723
724    sigjmp_buf              m_sigjmp_buf;
725    system_signal_exception m_sys_sig;
726
727    static signal_handler*  s_active_handler;
728};
729
730// !! need to be placed in thread specific storage
731typedef signal_handler* signal_handler_ptr;
732signal_handler* signal_handler::s_active_handler = signal_handler_ptr();
733
734//____________________________________________________________________________//
735
736signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack )
737: m_prev_handler( s_active_handler )
738, m_timeout( timeout )
739, m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack )
740, m_FPE_action ( SIGFPE , detect_fpe         , attach_dbg, alt_stack )
741, m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack )
742, m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack )
743#ifdef BOOST_TEST_CATCH_SIGPOLL
744, m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack )
745#endif
746, m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack )
747, m_ALRM_action( SIGALRM, timeout > 0        , attach_dbg, alt_stack )
748{
749    s_active_handler = this;
750
751    if( m_timeout > 0 ) {
752        ::alarm( 0 );
753        ::alarm( timeout );
754    }
755
756#ifdef BOOST_TEST_USE_ALT_STACK
757    if( alt_stack ) {
758        stack_t sigstk;
759        std::memset( &sigstk, 0, sizeof(stack_t) );
760
761        BOOST_TEST_SYS_ASSERT( ::sigaltstack( 0, &sigstk ) != -1 );
762
763        if( sigstk.ss_flags & SS_DISABLE ) {
764            sigstk.ss_sp    = alt_stack;
765            sigstk.ss_size  = BOOST_TEST_ALT_STACK_SIZE;
766            sigstk.ss_flags = 0;
767            BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 );
768        }
769    }
770#endif
771}
772
773//____________________________________________________________________________//
774
775signal_handler::~signal_handler()
776{
777    assert( s_active_handler == this );
778
779    if( m_timeout > 0 )
780        ::alarm( 0 );
781
782#ifdef BOOST_TEST_USE_ALT_STACK
783#ifdef __GNUC__
784    // We shouldn't need to explicitly initialize all the members here,
785    // but gcc warns if we don't, so add initializers for each of the
786    // members specified in the POSIX std:
787    stack_t sigstk = { 0, 0, 0 };
788#else
789    stack_t sigstk = { };
790#endif
791
792    sigstk.ss_size  = MINSIGSTKSZ;
793    sigstk.ss_flags = SS_DISABLE;
794    if( ::sigaltstack( &sigstk, 0 ) == -1 ) {
795        int error_n = errno;
796        std::cerr << "******** errors disabling the alternate stack:" << std::endl
797                  << "\t#error:" << error_n << std::endl
798                  << "\t" << std::strerror( error_n ) << std::endl;
799    }
800#endif
801
802    s_active_handler = m_prev_handler;
803}
804
805//____________________________________________________________________________//
806
807// ************************************************************************** //
808// **************       execution_monitor_signal_handler       ************** //
809// ************************************************************************** //
810
811extern "C" {
812
813static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context )
814{
815    signal_handler::sys_sig()( info, context );
816
817    siglongjmp( signal_handler::jump_buffer(), sig );
818}
819
820//____________________________________________________________________________//
821
822static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context )
823{
824    if( !debug::attach_debugger( false ) )
825        boost_execution_monitor_jumping_signal_handler( sig, info, context );
826
827    // debugger attached; it will handle the signal
828    BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR );
829}
830
831//____________________________________________________________________________//
832
833}
834
835} // namespace detail
836
837// ************************************************************************** //
838// **************        execution_monitor::catch_signals      ************** //
839// ************************************************************************** //
840
841int
842execution_monitor::catch_signals( boost::function<int ()> const& F )
843{
844    using namespace detail;
845
846#if defined(__CYGWIN__)
847    p_catch_system_errors.value = false;
848#endif
849
850#ifdef BOOST_TEST_USE_ALT_STACK
851    if( !!p_use_alt_stack && !m_alt_stack )
852        m_alt_stack.reset( new char[BOOST_TEST_ALT_STACK_SIZE] );
853#else
854    p_use_alt_stack.value = false;
855#endif
856
857    signal_handler local_signal_handler( p_catch_system_errors,
858                                         p_catch_system_errors || (p_detect_fp_exceptions != fpe::BOOST_FPE_OFF),
859                                         p_timeout,
860                                         p_auto_start_dbg,
861                                         !p_use_alt_stack ? 0 : m_alt_stack.get() );
862
863    if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) )
864        return detail::do_invoke( m_custom_translators , F );
865    else
866        BOOST_TEST_I_THROW( local_signal_handler.sys_sig() );
867}
868
869//____________________________________________________________________________//
870
871#elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING)
872
873// ************************************************************************** //
874// **************   Microsoft structured exception handling    ************** //
875// ************************************************************************** //
876
877#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564))
878namespace { void _set_se_translator( void* ) {} }
879#endif
880
881namespace detail {
882
883// ************************************************************************** //
884// **************    boost::detail::system_signal_exception    ************** //
885// ************************************************************************** //
886
887class system_signal_exception {
888public:
889    // Constructor
890    explicit            system_signal_exception( execution_monitor* em )
891    : m_em( em )
892    , m_se_id( 0 )
893    , m_fault_address( 0 )
894    , m_dir( false )
895    {}
896
897    void                report() const;
898    int                 operator()( unsigned id, _EXCEPTION_POINTERS* exps );
899
900private:
901    // Data members
902    execution_monitor*  m_em;
903
904    unsigned            m_se_id;
905    void*               m_fault_address;
906    bool                m_dir;
907};
908
909//____________________________________________________________________________//
910
911#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310)
912static void
913seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ )
914{
915    throw;
916}
917#endif
918
919//____________________________________________________________________________//
920
921int
922system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps )
923{
924    const unsigned MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC
925
926    // C++ exception - allow to go through
927    if( id == MSFT_CPP_EXCEPT )
928        return EXCEPTION_CONTINUE_SEARCH;
929
930    // FPE detection is enabled, while system exception detection is not - check if this is actually FPE
931    if( !m_em->p_catch_system_errors ) {
932        if( !m_em->p_detect_fp_exceptions )
933            return EXCEPTION_CONTINUE_SEARCH;
934
935        switch( id ) {
936        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
937        case EXCEPTION_FLT_STACK_CHECK:
938        case EXCEPTION_FLT_DENORMAL_OPERAND:
939        case EXCEPTION_FLT_INEXACT_RESULT:
940        case EXCEPTION_FLT_OVERFLOW:
941        case EXCEPTION_FLT_UNDERFLOW:
942        case EXCEPTION_FLT_INVALID_OPERATION:
943        case STATUS_FLOAT_MULTIPLE_FAULTS:
944        case STATUS_FLOAT_MULTIPLE_TRAPS:
945            break;
946        default:
947            return EXCEPTION_CONTINUE_SEARCH;
948        }
949    }
950
951    if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) {
952        m_em->p_catch_system_errors.value = false;
953#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310)
954        _set_se_translator( &seh_catch_preventer );
955#endif
956        return EXCEPTION_CONTINUE_EXECUTION;
957    }
958
959    m_se_id = id;
960    if( m_se_id == EXCEPTION_ACCESS_VIOLATION && exps->ExceptionRecord->NumberParameters == 2 ) {
961        m_fault_address = (void*)exps->ExceptionRecord->ExceptionInformation[1];
962        m_dir           = exps->ExceptionRecord->ExceptionInformation[0] == 0;
963    }
964
965    return EXCEPTION_EXECUTE_HANDLER;
966}
967
968//____________________________________________________________________________//
969
970void
971system_signal_exception::report() const
972{
973    switch( m_se_id ) {
974    // cases classified as system_fatal_error
975    case EXCEPTION_ACCESS_VIOLATION: {
976        if( !m_fault_address )
977            detail::report_error( execution_exception::system_fatal_error, "memory access violation" );
978        else
979            detail::report_error(
980                execution_exception::system_fatal_error,
981                    "memory access violation occurred at address 0x%08lx, while attempting to %s",
982                    m_fault_address,
983                    m_dir ? " read inaccessible data"
984                          : " write to an inaccessible (or protected) address"
985                    );
986        break;
987    }
988
989    case EXCEPTION_ILLEGAL_INSTRUCTION:
990        detail::report_error( execution_exception::system_fatal_error, "illegal instruction" );
991        break;
992
993    case EXCEPTION_PRIV_INSTRUCTION:
994        detail::report_error( execution_exception::system_fatal_error, "tried to execute an instruction whose operation is not allowed in the current machine mode" );
995        break;
996
997    case EXCEPTION_IN_PAGE_ERROR:
998        detail::report_error( execution_exception::system_fatal_error, "access to a memory page that is not present" );
999        break;
1000
1001    case EXCEPTION_STACK_OVERFLOW:
1002        detail::report_error( execution_exception::system_fatal_error, "stack overflow" );
1003        break;
1004
1005    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
1006        detail::report_error( execution_exception::system_fatal_error, "tried to continue execution after a non continuable exception occurred" );
1007        break;
1008
1009    // cases classified as (non-fatal) system_trap
1010    case EXCEPTION_DATATYPE_MISALIGNMENT:
1011        detail::report_error( execution_exception::system_error, "data misalignment" );
1012        break;
1013
1014    case EXCEPTION_INT_DIVIDE_BY_ZERO:
1015        detail::report_error( execution_exception::system_error, "integer divide by zero" );
1016        break;
1017
1018    case EXCEPTION_INT_OVERFLOW:
1019        detail::report_error( execution_exception::system_error, "integer overflow" );
1020        break;
1021
1022    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1023        detail::report_error( execution_exception::system_error, "array bounds exceeded" );
1024        break;
1025
1026    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1027        detail::report_error( execution_exception::system_error, "floating point divide by zero" );
1028        break;
1029
1030    case EXCEPTION_FLT_STACK_CHECK:
1031        detail::report_error( execution_exception::system_error,
1032                              "stack overflowed or underflowed as the result of a floating-point operation" );
1033        break;
1034
1035    case EXCEPTION_FLT_DENORMAL_OPERAND:
1036        detail::report_error( execution_exception::system_error,
1037                              "operand of floating point operation is denormal" );
1038        break;
1039
1040    case EXCEPTION_FLT_INEXACT_RESULT:
1041        detail::report_error( execution_exception::system_error,
1042                              "result of a floating-point operation cannot be represented exactly" );
1043        break;
1044
1045    case EXCEPTION_FLT_OVERFLOW:
1046        detail::report_error( execution_exception::system_error,
1047                              "exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type" );
1048        break;
1049
1050    case EXCEPTION_FLT_UNDERFLOW:
1051        detail::report_error( execution_exception::system_error,
1052                              "exponent of a floating-point operation is less than the magnitude allowed by the corresponding type" );
1053        break;
1054
1055    case EXCEPTION_FLT_INVALID_OPERATION:
1056        detail::report_error( execution_exception::system_error, "floating point error" );
1057        break;
1058
1059    case STATUS_FLOAT_MULTIPLE_FAULTS:
1060        detail::report_error( execution_exception::system_error, "multiple floating point errors" );
1061        break;
1062
1063    case STATUS_FLOAT_MULTIPLE_TRAPS:
1064        detail::report_error( execution_exception::system_error, "multiple floating point errors" );
1065        break;
1066
1067    case EXCEPTION_BREAKPOINT:
1068        detail::report_error( execution_exception::system_error, "breakpoint encountered" );
1069        break;
1070
1071    default:
1072        detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id );
1073        break;
1074    }
1075}
1076
1077//____________________________________________________________________________//
1078
1079// ************************************************************************** //
1080// **************          assert_reporting_function           ************** //
1081// ************************************************************************** //
1082
1083int BOOST_TEST_CALL_DECL
1084assert_reporting_function( int reportType, char* userMessage, int* )
1085{
1086    // write this way instead of switch to avoid unreachable statements
1087    if( reportType == BOOST_TEST_CRT_ASSERT || reportType == BOOST_TEST_CRT_ERROR )
1088        detail::report_error( reportType == BOOST_TEST_CRT_ASSERT ? execution_exception::user_error : execution_exception::system_error, userMessage );
1089
1090    return 0;
1091} // assert_reporting_function
1092
1093//____________________________________________________________________________//
1094
1095void BOOST_TEST_CALL_DECL
1096invalid_param_handler( wchar_t const* /* expr */,
1097                       wchar_t const* /* func */,
1098                       wchar_t const* /* file */,
1099                       unsigned       /* line */,
1100                       uintptr_t      /* reserved */)
1101{
1102    detail::report_error( execution_exception::user_error,
1103                          "Invalid parameter detected by C runtime library" );
1104}
1105
1106//____________________________________________________________________________//
1107
1108} // namespace detail
1109
1110// ************************************************************************** //
1111// **************        execution_monitor::catch_signals      ************** //
1112// ************************************************************************** //
1113
1114int
1115execution_monitor::catch_signals( boost::function<int ()> const& F )
1116{
1117    _invalid_parameter_handler old_iph = _invalid_parameter_handler();
1118    BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0;
1119
1120    if( p_catch_system_errors ) {
1121        old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function );
1122
1123        old_iph = _set_invalid_parameter_handler(
1124            reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) );
1125    } else if( !p_detect_fp_exceptions ) {
1126#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310)
1127        _set_se_translator( &detail::seh_catch_preventer );
1128#endif
1129    }
1130
1131    detail::system_signal_exception SSE( this );
1132
1133    int ret_val = 0;
1134    // clang windows workaround: this not available in __finally scope
1135    bool l_catch_system_errors = p_catch_system_errors;
1136
1137    __try {
1138        __try {
1139            ret_val = detail::do_invoke( m_custom_translators, F );
1140        }
1141        __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) {
1142            throw SSE;
1143        }
1144    }
1145    __finally {
1146        if( l_catch_system_errors ) {
1147            BOOST_TEST_CRT_SET_HOOK( old_crt_hook );
1148
1149           _set_invalid_parameter_handler( old_iph );
1150        }
1151    }
1152
1153    return ret_val;
1154}
1155
1156//____________________________________________________________________________//
1157
1158#else  // default signal handler
1159
1160namespace detail {
1161
1162class system_signal_exception {
1163public:
1164    void   report() const {}
1165};
1166
1167} // namespace detail
1168
1169int
1170execution_monitor::catch_signals( boost::function<int ()> const& F )
1171{
1172    return detail::do_invoke( m_custom_translators , F );
1173}
1174
1175//____________________________________________________________________________//
1176
1177#endif  // choose signal handler
1178
1179// ************************************************************************** //
1180// **************              execution_monitor               ************** //
1181// ************************************************************************** //
1182
1183execution_monitor::execution_monitor()
1184: p_catch_system_errors( true )
1185, p_auto_start_dbg( false )
1186, p_timeout( 0 )
1187, p_use_alt_stack( true )
1188, p_detect_fp_exceptions( fpe::BOOST_FPE_OFF )
1189{}
1190
1191//____________________________________________________________________________//
1192
1193int
1194execution_monitor::execute( boost::function<int ()> const& F )
1195{
1196    if( debug::under_debugger() )
1197        p_catch_system_errors.value = false;
1198
1199    BOOST_TEST_I_TRY {
1200        detail::fpe_except_guard G( p_detect_fp_exceptions );
1201        unit_test::ut_detail::ignore_unused_variable_warning( G );
1202
1203        return catch_signals( F );
1204    }
1205
1206#ifndef BOOST_NO_EXCEPTIONS
1207
1208    //  Catch-clause reference arguments are a bit different from function
1209    //  arguments (ISO 15.3 paragraphs 18 & 19).  Apparently const isn't
1210    //  required.  Programmers ask for const anyhow, so we supply it.  That's
1211    //  easier than answering questions about non-const usage.
1212
1213    catch( char const* ex )
1214      { detail::report_error( execution_exception::cpp_exception_error,
1215                              "C string: %s", ex ); }
1216    catch( std::string const& ex )
1217      { detail::report_error( execution_exception::cpp_exception_error,
1218                              "std::string: %s", ex.c_str() ); }
1219
1220    //  std:: exceptions
1221#if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI)
1222#define CATCH_AND_REPORT_STD_EXCEPTION( ex_name )                           \
1223    catch( ex_name const& ex )                                              \
1224       { detail::report_error( execution_exception::cpp_exception_error,    \
1225                          current_exception_cast<boost::exception const>(), \
1226                          #ex_name ": %s", ex.what() ); }                   \
1227/**/
1228#else
1229#define CATCH_AND_REPORT_STD_EXCEPTION( ex_name )                           \
1230    catch( ex_name const& ex )                                              \
1231        { detail::report_error( execution_exception::cpp_exception_error,   \
1232                          current_exception_cast<boost::exception const>(), \
1233                          "%s: %s", detail::typeid_name(ex).c_str(), ex.what() ); } \
1234/**/
1235#endif
1236
1237    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc )
1238
1239#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
1240    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast )
1241    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid )
1242#else
1243    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast )
1244    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid )
1245#endif
1246
1247    CATCH_AND_REPORT_STD_EXCEPTION( std::bad_exception )
1248    CATCH_AND_REPORT_STD_EXCEPTION( std::domain_error )
1249    CATCH_AND_REPORT_STD_EXCEPTION( std::invalid_argument )
1250    CATCH_AND_REPORT_STD_EXCEPTION( std::length_error )
1251    CATCH_AND_REPORT_STD_EXCEPTION( std::out_of_range )
1252    CATCH_AND_REPORT_STD_EXCEPTION( std::range_error )
1253    CATCH_AND_REPORT_STD_EXCEPTION( std::overflow_error )
1254    CATCH_AND_REPORT_STD_EXCEPTION( std::underflow_error )
1255    CATCH_AND_REPORT_STD_EXCEPTION( std::logic_error )
1256    CATCH_AND_REPORT_STD_EXCEPTION( std::runtime_error )
1257    CATCH_AND_REPORT_STD_EXCEPTION( std::exception )
1258#undef CATCH_AND_REPORT_STD_EXCEPTION
1259
1260    catch( boost::exception const& ex )
1261      { detail::report_error( execution_exception::cpp_exception_error,
1262                              &ex,
1263#if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI)
1264                              "unknown boost::exception" ); }
1265#else
1266                              typeid(ex).name()          ); }
1267#endif
1268
1269    // system errors
1270    catch( system_error const& ex )
1271      { detail::report_error( execution_exception::cpp_exception_error,
1272                              "system_error produced by: %s: %s", ex.p_failed_exp, std::strerror( ex.p_errno ) ); }
1273    catch( detail::system_signal_exception const& ex )
1274      { ex.report(); }
1275
1276    // not an error
1277    catch( execution_aborted const& )
1278      { return 0; }
1279
1280    // just forward
1281    catch( execution_exception const& )
1282      { throw; }
1283
1284    // unknown error
1285    catch( ... )
1286      { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); }
1287
1288#endif // !BOOST_NO_EXCEPTIONS
1289
1290    return 0;  // never reached; supplied to quiet compiler warnings
1291} // execute
1292
1293//____________________________________________________________________________//
1294
1295namespace detail {
1296
1297struct forward {
1298    explicit    forward( boost::function<void ()> const& F ) : m_F( F ) {}
1299
1300    int         operator()() { m_F(); return 0; }
1301
1302    boost::function<void ()> const& m_F;
1303};
1304
1305} // namespace detail
1306void
1307execution_monitor::vexecute( boost::function<void ()> const& F )
1308{
1309    execute( detail::forward( F ) );
1310}
1311
1312// ************************************************************************** //
1313// **************                  system_error                ************** //
1314// ************************************************************************** //
1315
1316system_error::system_error( char const* exp )
1317#ifdef UNDER_CE
1318: p_errno( GetLastError() )
1319#else
1320: p_errno( errno )
1321#endif
1322, p_failed_exp( exp )
1323{}
1324
1325//____________________________________________________________________________//
1326
1327// ************************************************************************** //
1328// **************              execution_exception             ************** //
1329// ************************************************************************** //
1330
1331execution_exception::execution_exception( error_code ec_, const_string what_msg_, location const& location_ )
1332: m_error_code( ec_ )
1333, m_what( what_msg_.empty() ? BOOST_TEST_L( "uncaught exception, system error or abort requested" ) : what_msg_ )
1334, m_location( location_ )
1335{}
1336
1337//____________________________________________________________________________//
1338
1339execution_exception::location::location( char const* file_name, size_t line_num, char const* func )
1340: m_file_name( file_name ? file_name : "unknown location" )
1341, m_line_num( line_num )
1342, m_function( func )
1343{}
1344
1345execution_exception::location::location(const_string file_name, size_t line_num, char const* func )
1346: m_file_name( file_name )
1347, m_line_num( line_num )
1348, m_function( func )
1349{}
1350
1351//____________________________________________________________________________//
1352
1353// ************************************************************************** //
1354// **************Floating point exception management interface ************** //
1355// ************************************************************************** //
1356
1357namespace fpe {
1358
1359unsigned
1360enable( unsigned mask )
1361{
1362    boost::ignore_unused(mask);
1363#if defined(BOOST_TEST_FPE_SUPPORT_WITH_SEH__)
1364    _clearfp();
1365
1366#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310)
1367    unsigned old_cw = ::_controlfp( 0, 0 );
1368    ::_controlfp( old_cw & ~mask, BOOST_FPE_ALL );
1369#else
1370    unsigned old_cw;
1371    if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 )
1372        return BOOST_FPE_INV;
1373
1374    // Set the control word
1375    if( ::_controlfp_s( 0, old_cw & ~mask, BOOST_FPE_ALL ) != 0 )
1376        return BOOST_FPE_INV;
1377#endif
1378    return ~old_cw & BOOST_FPE_ALL;
1379
1380#elif defined(BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__)
1381    // same macro definition as in execution_monitor.hpp
1382    if (BOOST_FPE_ALL == BOOST_FPE_OFF)
1383        /* Not Implemented */
1384        return BOOST_FPE_OFF;
1385    feclearexcept(BOOST_FPE_ALL);
1386    int res = feenableexcept( mask );
1387    return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res;
1388#else
1389    /* Not Implemented  */
1390    return BOOST_FPE_OFF;
1391#endif
1392}
1393
1394//____________________________________________________________________________//
1395
1396unsigned
1397disable( unsigned mask )
1398{
1399    boost::ignore_unused(mask);
1400
1401#if defined(BOOST_TEST_FPE_SUPPORT_WITH_SEH__)
1402    _clearfp();
1403#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310)
1404    unsigned old_cw = ::_controlfp( 0, 0 );
1405    ::_controlfp( old_cw | mask, BOOST_FPE_ALL );
1406#else
1407    unsigned old_cw;
1408    if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 )
1409        return BOOST_FPE_INV;
1410
1411    // Set the control word
1412    if( ::_controlfp_s( 0, old_cw | mask, BOOST_FPE_ALL ) != 0 )
1413        return BOOST_FPE_INV;
1414#endif
1415    return ~old_cw & BOOST_FPE_ALL;
1416
1417#elif defined(BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__)
1418    if (BOOST_FPE_ALL == BOOST_FPE_OFF)
1419        /* Not Implemented */
1420        return BOOST_FPE_INV;
1421    feclearexcept(BOOST_FPE_ALL);
1422    int res = fedisableexcept( mask );
1423    return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res;
1424#else
1425    /* Not Implemented */
1426    return BOOST_FPE_INV;
1427#endif
1428}
1429
1430//____________________________________________________________________________//
1431
1432} // namespace fpe
1433
1434} // namespace boost
1435
1436#include <boost/test/detail/enable_warnings.hpp>
1437
1438#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
1439