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

source code of boost/boost/test/execution_monitor.hpp