execution_monitor.hpp 24 KB

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