1 //  (C) Copyright Gennadiy Rozental 2001.
2 //  (C) Copyright Beman Dawes 2001.
3 //  Distributed under the Boost Software License, Version 1.0.
4 //  (See accompanying file LICENSE_1_0.txt or copy at
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 //!@brief Defines public interface of the Execution Monitor and related classes
11 // ***************************************************************************
12 
13 #ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
14 #define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
15 
16 // Boost.Test
17 #include <boost/test/detail/global_typedef.hpp>
18 #include <boost/test/detail/fwd_decl.hpp>
19 #include <boost/test/detail/throw_exception.hpp>
20 
21 #include <boost/test/utils/class_properties.hpp>
22 
23 // Boost
24 #include <boost/shared_ptr.hpp>
25 #include <boost/scoped_array.hpp>
26 #include <boost/type.hpp>
27 #include <boost/cstdlib.hpp>
28 #include <boost/function/function0.hpp>
29 
30 #include <boost/test/detail/suppress_warnings.hpp>
31 
32 #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
33 
34 // for the FP constants and control routines
35 #include <float.h>
36 
37 #ifndef EM_INVALID
38 #define EM_INVALID _EM_INVALID
39 #endif
40 
41 #ifndef EM_DENORMAL
42 #define EM_DENORMAL _EM_DENORMAL
43 #endif
44 
45 #ifndef EM_ZERODIVIDE
46 #define EM_ZERODIVIDE _EM_ZERODIVIDE
47 #endif
48 
49 #ifndef EM_OVERFLOW
50 #define EM_OVERFLOW _EM_OVERFLOW
51 #endif
52 
53 #ifndef EM_UNDERFLOW
54 #define EM_UNDERFLOW _EM_UNDERFLOW
55 #endif
56 
57 #ifndef MCW_EM
58 #define MCW_EM _MCW_EM
59 #endif
60 
61 #else // based on ISO C standard
62 
63 #if !defined(BOOST_NO_FENV_H)
64   #include <boost/detail/fenv.hpp>
65 #endif
66 
67 #endif
68 
69 
70 // Additional macro documentations not being generated without this hack
71 #ifdef BOOST_TEST_DOXYGEN_DOC__
72 
73 //! Disables the support of the alternative stack
74 //! during the compilation of the Boost.test framework. This is especially useful
75 //! in case it is not possible to detect the lack of alternative stack support for
76 //! your compiler (for instance, ESXi).
77 #define BOOST_TEST_DISABLE_ALT_STACK
78 
79 #endif
80 
81 //____________________________________________________________________________//
82 
83 namespace boost {
84 
85 /// @defgroup ExecutionMonitor Function Execution Monitor
86 /// @{
87 /// @section Intro Introduction
88 /// Sometimes we need to call a function and make sure that no user or system originated exceptions are being thrown by it. Uniform exception reporting
89 /// is also may be convenient. That's the purpose of the Boost.Test's Execution Monitor.
90 ///
91 /// The Execution Monitor is a lower-level component of the Boost Test Library. It is the base for implementing all other Boost.Test components, but also
92 /// can be used standalone to get controlled execution of error-prone functions with a uniform error notification. The Execution Monitor calls a user-supplied
93 /// function in a controlled environment, relieving users from messy error detection.
94 ///
95 /// The Execution Monitor usage is demonstrated in the example exec_mon_example.
96 ///
97 /// @section DesignRationale Design Rationale
98 ///
99 /// The Execution Monitor design assumes that it can be used when no (or almost no) memory available. Also the Execution Monitor is intended to be portable to as many platforms as possible.
100 ///
101 /// @section UserGuide User's guide
102 /// The Execution Monitor is designed to solve the problem of executing potentially dangerous function that may result in any number of error conditions,
103 /// in monitored environment that should prevent any undesirable exceptions to propagate out of function call and produce consistent result report for all outcomes.
104 /// The Execution Monitor is able to produce informative report for all standard C++ exceptions and intrinsic types. All other exceptions are reported as unknown.
105 /// If you prefer different message for your exception type or need to perform any action, the Execution Monitor supports custom exception translators.
106 /// There are several other parameters of the monitored environment can be configured by setting appropriate properties of the Execution Monitor.
107 ///
108 /// All symbols in the Execution Monitor implementation are located in the namespace boost. To use the Execution Monitor you need to:
109 /// -# include @c boost/test/execution_monitor.hpp
110 /// -# Make an instance of execution_monitor.
111 /// -# Optionally register custom exception translators for exception classes which require special processing.
112 ///
113 /// @subsection FuncExec Monitored function execution
114 ///
115 /// The class execution_monitor can monitor functions with the following signatures:
116 /// - int ()
117 /// - void ()
118 ///
119 /// This function is expected to be self sufficient part of your application. You can't pass any arguments to this function directly. Instead you
120 /// should bind them into executable nullary function using bind function (either standard or boost variant). Neither you can return any other value,
121 /// but an integer result code. If necessary you can bind output parameters by reference or use some other more complicated nullary functor, which
122 /// maintains state. This includes class methods, static class methods etc.
123 ///
124 /// To start the monitored function, invoke the method execution_monitor::execute and pass the monitored function as an argument. If the call succeeds,
125 /// the method returns the result code produced by the monitored function. If any of the following conditions occur:
126 /// - Uncaught C++ exception
127 /// - Hardware or software signal, trap, or other exception
128 /// - Timeout reached
129 /// - Debug assert event occurred (under Microsoft Visual C++ or compatible compiler)
130 ///
131 /// then the method throws the execution_exception. The exception contains unique error_code value identifying the error condition and the detailed message
132 /// that can be used to report the error.
133 ///
134 /// @subsection Reporting Errors reporting and translation
135 ///
136 /// If you need to report an error inside monitored function execution you have to throw an exception. Do not use the execution_exception - it's not intended
137 /// to be used for this purpose. The simplest choice is to use one of the following C++ types as an exception:
138 /// - C string
139 /// - std:string
140 /// - any exception class in std::exception hierarchy
141 /// - boost::exception
142 ///
143 /// execution_monitor will catch and report these types of exceptions. If exception is thrown which is unknown to execution_monitor, it can only
144 /// report the fact of the exception. So in case if you prefer to use your own exception types or can't govern what exceptions are generated by monitored
145 /// function and would like to see proper error message in a report, execution_monitor can be configured with custom "translator" routine, which will have
146 /// a chance to either record the fact of the exception itself or translate it into one of standard exceptions and rethrow (or both). The translator routine
147 /// is registered per exception type and is invoked when exception of this class (or one inherited from it) is thrown inside monitored routine. You can
148 /// register as many independent translators as you like. See execution_monitor::register_exception_translator specification for requirements on translator
149 /// function.
150 ///
151 /// Finally, if you need to abort the monitored function execution without reporting any errors, you can throw an exception execution_aborted. As a result
152 /// the execution is aborted and zero result code is produced by the method execution_monitor::execute.
153 ///
154 /// @subsection Parameters Supported parameters
155 ///
156 /// The Execution Monitor behavior is configurable through the set of parameters (properties) associated with the instance of the monitor. See execution_monitor
157 /// specification for a list of supported parameters and their semantic.
158 
159 // ************************************************************************** //
160 // **************        detail::translator_holder_base        ************** //
161 // ************************************************************************** //
162 
163 namespace detail {
164 
165 class translator_holder_base;
166 typedef boost::shared_ptr<translator_holder_base> translator_holder_base_ptr;
167 
168 class BOOST_TEST_DECL translator_holder_base {
169 protected:
170     typedef boost::unit_test::const_string const_string;
171 public:
172     // Constructor
translator_holder_base(translator_holder_base_ptr next,const_string tag)173     translator_holder_base( translator_holder_base_ptr next, const_string tag )
174     : m_next( next )
175     , m_tag( std::string() + tag )
176     {
177     }
178 
179     // Destructor
~translator_holder_base()180     virtual     ~translator_holder_base() {}
181 
182     // translator holder interface
183     // invokes the function F inside the try/catch guarding against specific exception
184     virtual int operator()( boost::function<int ()> const& F ) = 0;
185 
186     // erases specific translator holder from the chain
erase(translator_holder_base_ptr this_,const_string tag)187     translator_holder_base_ptr erase( translator_holder_base_ptr this_, const_string tag )
188     {
189         if( m_next )
190             m_next = m_next->erase( m_next, tag );
191 
192         return m_tag == tag ? m_next : this_;
193     }
194 #ifndef BOOST_NO_RTTI
195     virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ) = 0;
196     template<typename ExceptionType>
erase(translator_holder_base_ptr this_,boost::type<ExceptionType> * =0)197     translator_holder_base_ptr erase( translator_holder_base_ptr this_, boost::type<ExceptionType>* = 0 )
198     {
199         if( m_next )
200             m_next = m_next->erase<ExceptionType>( m_next );
201 
202         return erase( this_, typeid(ExceptionType) );
203     }
204 #endif
205 
206 protected:
207     // Data members
208     translator_holder_base_ptr  m_next;
209     std::string                 m_tag;
210 };
211 
212 } // namespace detail
213 
214 // ************************************************************************** //
215 /// @class execution_exception
216 /// @brief This class is used to report any kind of an failure during execution of a monitored function inside of execution_monitor
217 ///
218 /// The instance of this class is thrown out of execution_monitor::execute invocation when failure is detected. Regardless of a kind of failure occurred
219 /// the instance will provide a uniform way to catch and report it.
220 ///
221 /// One important design rationale for this class is that we should be ready to work after fatal memory corruptions or out of memory conditions. To facilitate
222 /// this class never allocates any memory and assumes that strings it refers to are either some constants or live in a some kind of persistent (preallocated) memory.
223 // ************************************************************************** //
224 
225 class BOOST_TEST_DECL execution_exception {
226     typedef boost::unit_test::const_string const_string;
227 public:
228     /// These values are sometimes used as program return codes.
229     /// The particular values have been chosen to avoid conflicts with
230     /// commonly used program return codes: values < 100 are often user
231     /// assigned, values > 255 are sometimes used to report system errors.
232     /// Gaps in values allow for orderly expansion.
233     ///
234     /// @note(1) Only uncaught C++ exceptions are treated as errors.
235     /// If a function catches a C++ exception, it never reaches
236     /// the execution_monitor.
237     ///
238     /// The implementation decides what is a system_fatal_error and what is
239     /// just a system_exception. Fatal errors are so likely to have corrupted
240     /// machine state (like a stack overflow or addressing exception) that it
241     /// is unreasonable to continue execution.
242     ///
243     /// @note(2) These errors include Unix signals and Windows structured
244     /// exceptions. They are often initiated by hardware traps.
245     enum error_code {
246         no_error               = 0,   ///< for completeness only; never returned
247         user_error             = 200, ///< user reported non-fatal error
248         cpp_exception_error    = 205, ///< see note (1) above
249         system_error           = 210, ///< see note (2) above
250         timeout_error          = 215, ///< only detectable on certain platforms
251         user_fatal_error       = 220, ///< user reported fatal error
252         system_fatal_error     = 225  ///< see note (2) above
253     };
254 
255     /// Simple model for the location of failure in a source code
256     struct BOOST_TEST_DECL location {
257         explicit    location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 );
258 
259         const_string    m_file_name;    ///< File name
260         size_t          m_line_num;     ///< Line number
261         const_string    m_function;     ///< Function name
262     };
263 
264     /// @name Constructors
265 
266     /// Constructs instance based on message, location and error code
267 
268     /// @param[in] ec           error code
269     /// @param[in] what_msg     error message
270     /// @param[in] location     error location
271     execution_exception( error_code ec, const_string what_msg, location const& location );
272 
273     /// @name Access methods
274 
275     /// Exception error code
code() const276     error_code      code() const    { return m_error_code; }
277     /// Exception message
what() const278     const_string    what() const    { return m_what; }
279     /// Exception location
where() const280     location const& where() const   { return m_location; }
281     ///@}
282 
283 private:
284     // Data members
285     error_code      m_error_code;
286     const_string    m_what;
287     location        m_location;
288 }; // execution_exception
289 
290 // ************************************************************************** //
291 /// @brief Function execution monitor
292 
293 /// This class is used to uniformly detect and report an occurrence of several types of signals and exceptions, reducing various
294 /// errors to a uniform execution_exception that is returned to a caller.
295 ///
296 /// The executiom_monitor behavior can be customized through a set of public parameters (properties) associated with the execution_monitor instance.
297 /// All parameters are implemented as public unit_test::readwrite_property data members of the class execution_monitor.
298 // ************************************************************************** //
299 
300 class BOOST_TEST_DECL execution_monitor {
301     typedef boost::unit_test::const_string const_string;
302 public:
303 
304     /// Default constructor initializes all execution monitor properties
305     execution_monitor();
306 
307     /// Should monitor catch system errors.
308     ///
309     /// The @em p_catch_system_errors property is a boolean flag (default value is true) specifying whether or not execution_monitor should trap system
310     /// errors/system level exceptions/signals, which would cause program to crash in a regular case (without execution_monitor).
311     /// Set this property to false, for example, if you wish to force coredump file creation. The Unit Test Framework provides a
312     /// runtime parameter @c \-\-catch_system_errors=yes to alter the behavior in monitored test cases.
313     unit_test::readwrite_property<bool> p_catch_system_errors;
314 
315     ///  Should monitor try to attach debugger in case of caught system error.
316     ///
317     /// The @em p_auto_start_dbg property is a boolean flag (default value is false) specifying whether or not execution_monitor should try to attach debugger
318     /// in case system error is caught.
319     unit_test::readwrite_property<bool> p_auto_start_dbg;
320 
321 
322     ///  Specifies the seconds that elapse before a timer_error occurs.
323     ///
324     /// The @em p_timeout property is an integer timeout (in seconds) for monitored function execution. Use this parameter to monitor code with possible deadlocks
325     /// or indefinite loops. This feature is only available for some operating systems (not yet Microsoft Windows).
326     unit_test::readwrite_property<unsigned>  p_timeout;
327 
328     ///  Should monitor use alternative stack for the signal catching.
329     ///
330     /// The @em p_use_alt_stack property is a boolean flag (default value is false) specifying whether or not execution_monitor should use an alternative stack
331     /// for the sigaction based signal catching. When enabled the signals are delivered to the execution_monitor on a stack different from current execution
332     /// stack, which is safer in case if it is corrupted by monitored function. For more details on alternative stack handling see appropriate manuals.
333     unit_test::readwrite_property<bool> p_use_alt_stack;
334 
335     /// Should monitor try to detect hardware floating point exceptions (!= 0), and which specific exception to catch.
336     ///
337     /// The @em p_detect_fp_exceptions property is a boolean flag (default value is false) specifying whether or not execution_monitor should install hardware
338     /// traps for the floating point exception on platforms where it's supported.
339     unit_test::readwrite_property<unsigned> p_detect_fp_exceptions;
340 
341 
342     // @name Monitoring entry points
343 
344     /// @brief Execution monitor entry point for functions returning integer value
345     ///
346     /// This method executes supplied function F inside a try/catch block and also may include other unspecified platform dependent error detection code.
347     ///
348     /// This method throws an execution_exception on an uncaught C++ exception, a hardware or software signal, trap, or other user exception.
349     ///
350     /// @note execute() doesn't consider it an error for F to return a non-zero value.
351     /// @param[in] F  Function to monitor
352     /// @returns  value returned by function call F().
353     /// @see vexecute
354     int         execute( boost::function<int ()> const& F );
355 
356     /// @brief Execution monitor entry point for functions returning void
357     ///
358     /// This method is semantically identical to execution_monitor::execute, but des't produce any result code.
359     /// @param[in] F  Function to monitor
360     /// @see execute
361     void         vexecute( boost::function<void ()> const& F );
362     // @}
363 
364     // @name Exception translator registration
365 
366     /// @brief Registers custom (user supplied) exception translator
367 
368     /// This method template registers a translator for an exception type specified as a first template argument. For example
369     /// @code
370     ///    void myExceptTr( MyException const& ex ) { /*do something with the exception here*/}
371     ///    em.register_exception_translator<MyException>( myExceptTr );
372     /// @endcode
373     /// The translator should be any unary function/functor object which accepts MyException const&. This can be free standing function
374     /// or bound class method. The second argument is an optional string tag you can associate with this translator routine. The only reason
375     /// to specify the tag is if you plan to erase the translator eventually. This can be useful in scenario when you reuse the same
376     /// execution_monitor instance to monitor different routines and need to register a translator specific to the routine being monitored.
377     /// While it is possible to erase the translator based on an exception type it was registered for, tag string provides simpler way of doing this.
378     /// @tparam ExceptionType type of the exception we register a translator for
379     /// @tparam ExceptionTranslator type of the translator we register for this exception
380     /// @param[in] tr         translator function object with the signature <em> void (ExceptionType const&)</em>
381     /// @param[in] tag        tag associated with this translator
382     template<typename ExceptionType, typename ExceptionTranslator>
383     void        register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 );
384 
385     /// @brief Erases custom exception translator based on a tag
386 
387     /// Use the same tag as the one used during translator registration
388     /// @param[in] tag  tag associated with translator you wants to erase
erase_exception_translator(const_string tag)389     void        erase_exception_translator( const_string tag )
390     {
391         m_custom_translators = m_custom_translators->erase( m_custom_translators, tag );
392     }
393 #ifndef BOOST_NO_RTTI
394     /// @brief Erases custom exception translator based on an exception type
395     ///
396     /// tparam ExceptionType Exception type for which you want to erase the translator
397     template<typename ExceptionType>
erase_exception_translator(boost::type<ExceptionType> * =0)398     void        erase_exception_translator( boost::type<ExceptionType>* = 0 )
399     {
400         m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators );
401     }
402     //@}
403 #endif
404 
405 private:
406     // implementation helpers
407     int         catch_signals( boost::function<int ()> const& F );
408 
409     // Data members
410     detail::translator_holder_base_ptr  m_custom_translators;
411     boost::scoped_array<char>           m_alt_stack;
412 }; // execution_monitor
413 
414 // ************************************************************************** //
415 // **************          detail::translator_holder           ************** //
416 // ************************************************************************** //
417 
418 namespace detail {
419 
420 template<typename ExceptionType, typename ExceptionTranslator>
421 class translator_holder : public translator_holder_base
422 {
423 public:
translator_holder(ExceptionTranslator const & tr,translator_holder_base_ptr & next,const_string tag=const_string ())424     explicit    translator_holder( ExceptionTranslator const& tr, translator_holder_base_ptr& next, const_string tag = const_string() )
425     : translator_holder_base( next, tag ), m_translator( tr ) {}
426 
427     // translator holder interface
operator ()(boost::function<int ()> const & F)428     virtual int operator()( boost::function<int ()> const& F )
429     {
430         BOOST_TEST_I_TRY {
431             return m_next ? (*m_next)( F ) : F();
432         }
433         BOOST_TEST_I_CATCH( ExceptionType, e ) {
434             m_translator( e );
435             return boost::exit_exception_failure;
436         }
437     }
438 #ifndef BOOST_NO_RTTI
erase(translator_holder_base_ptr this_,std::type_info const & ti)439     virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ti )
440     {
441         return ti == typeid(ExceptionType) ? m_next : this_;
442     }
443 #endif
444 
445 private:
446     // Data members
447     ExceptionTranslator m_translator;
448 };
449 
450 } // namespace detail
451 
452 template<typename ExceptionType, typename ExceptionTranslator>
453 void
register_exception_translator(ExceptionTranslator const & tr,const_string tag,boost::type<ExceptionType> *)454 execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* )
455 {
456     m_custom_translators.reset(
457         new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) );
458 }
459 
460 // ************************************************************************** //
461 /// @class execution_aborted
462 /// @brief This is a trivial default constructible class. Use it to report graceful abortion of a monitored function execution.
463 // ************************************************************************** //
464 
465 struct execution_aborted {};
466 
467 // ************************************************************************** //
468 // **************                  system_error                ************** //
469 // ************************************************************************** //
470 
471 class system_error {
472 public:
473     // Constructor
474     explicit    system_error( char const* exp );
475 
476     long const          p_errno;
477     char const* const   p_failed_exp;
478 };
479 
480 //!@internal
481 #define BOOST_TEST_SYS_ASSERT( cond ) BOOST_TEST_I_ASSRT( cond, ::boost::system_error( BOOST_STRINGIZE( exp ) ) )
482 
483 // ************************************************************************** //
484 // **************Floating point exception management interface ************** //
485 // ************************************************************************** //
486 
487 namespace fpe {
488 
489 enum masks {
490     BOOST_FPE_OFF       = 0,
491 
492 #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
493     BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE,
494     BOOST_FPE_INEXACT   = EM_INEXACT,
495     BOOST_FPE_INVALID   = EM_INVALID,
496     BOOST_FPE_OVERFLOW  = EM_OVERFLOW,
497     BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL,
498 
499     BOOST_FPE_ALL       = MCW_EM,
500 #elif defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG)
501     BOOST_FPE_ALL       = 1,
502 #else
503     BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
504     BOOST_FPE_INEXACT   = FE_INEXACT,
505     BOOST_FPE_INVALID   = FE_INVALID,
506     BOOST_FPE_OVERFLOW  = FE_OVERFLOW,
507     BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,
508 
509     BOOST_FPE_ALL       = FE_ALL_EXCEPT,
510 #endif
511     BOOST_FPE_INV       = BOOST_FPE_ALL+1
512 };
513 
514 //____________________________________________________________________________//
515 
516 // return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise
517 unsigned BOOST_TEST_DECL enable( unsigned mask );
518 unsigned BOOST_TEST_DECL disable( unsigned mask );
519 
520 //____________________________________________________________________________//
521 
522 } // namespace fpe
523 
524 ///@}
525 
526 }  // namespace boost
527 
528 
529 #include <boost/test/detail/enable_warnings.hpp>
530 
531 #endif
532