trap.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // trap.h - written and placed in public domain by Jeffrey Walton.
  2. /// \file trap.h
  3. /// \brief Debugging and diagnostic assertions
  4. /// \details <tt>CRYPTOPP_ASSERT</tt> is the library's debugging and diagnostic
  5. /// assertion. <tt>CRYPTOPP_ASSERT</tt> is enabled by <tt>CRYPTOPP_DEBUG</tt>,
  6. /// <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
  7. /// \details <tt>CRYPTOPP_ASSERT</tt> raises a <tt>SIGTRAP</tt> (Unix) or calls
  8. /// <tt>DebugBreak()</tt> (Windows).
  9. /// \details <tt>CRYPTOPP_ASSERT</tt> is only in effect when the user requests a
  10. /// debug configuration. <tt>NDEBUG</tt> (or failure to define it) does not
  11. /// affect <tt>CRYPTOPP_ASSERT</tt>.
  12. /// \since Crypto++ 5.6.5
  13. /// \sa DebugTrapHandler, <A
  14. /// HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
  15. /// <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>
  16. #ifndef CRYPTOPP_TRAP_H
  17. #define CRYPTOPP_TRAP_H
  18. #include "config.h"
  19. #if defined(CRYPTOPP_DEBUG)
  20. # include <iostream>
  21. # include <sstream>
  22. # if defined(UNIX_SIGNALS_AVAILABLE)
  23. # include "ossig.h"
  24. # elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__)
  25. extern "C" __declspec(dllimport) void __stdcall DebugBreak();
  26. extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
  27. # endif
  28. #endif // CRYPTOPP_DEBUG
  29. // ************** run-time assertion ***************
  30. #if defined(CRYPTOPP_DOXYGEN_PROCESSING)
  31. /// \brief Debugging and diagnostic assertion
  32. /// \details <tt>CRYPTOPP_ASSERT</tt> is the library's debugging and diagnostic
  33. /// assertion. <tt>CRYPTOPP_ASSERT</tt> is enabled by the preprocessor macros
  34. /// <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
  35. /// \details <tt>CRYPTOPP_ASSERT</tt> raises a <tt>SIGTRAP</tt> (Unix) or calls
  36. /// <tt>DebugBreak()</tt> (Windows). <tt>CRYPTOPP_ASSERT</tt> is only in effect
  37. /// when the user explicitly requests a debug configuration.
  38. /// \details If you want to ensure <tt>CRYPTOPP_ASSERT</tt> is inert, then <em>do
  39. /// not</em> define <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
  40. /// Avoiding the defines means <tt>CRYPTOPP_ASSERT</tt> is preprocessed into an
  41. /// empty string.
  42. /// \details The traditional Posix define <tt>NDEBUG</tt> has no effect on
  43. /// <tt>CRYPTOPP_DEBUG</tt>, <tt>CRYPTOPP_ASSERT</tt> or DebugTrapHandler.
  44. /// \details An example of using CRYPTOPP_ASSERT and DebugTrapHandler is shown
  45. /// below. The library's test program, <tt>cryptest.exe</tt> (from test.cpp),
  46. /// exercises the structure:
  47. /// <pre>
  48. /// \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
  49. /// static const DebugTrapHandler g_dummyHandler;
  50. /// \#endif
  51. ///
  52. /// int main(int argc, char* argv[])
  53. /// {
  54. /// CRYPTOPP_ASSERT(argv != nullptr);
  55. /// ...
  56. /// }
  57. /// </pre>
  58. /// \since Crypto++ 5.6.5
  59. /// \sa DebugTrapHandler, SignalHandler, <A
  60. /// HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
  61. /// <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>
  62. # define CRYPTOPP_ASSERT(exp) { ... }
  63. #endif
  64. #if defined(CRYPTOPP_DEBUG)
  65. # if defined(UNIX_SIGNALS_AVAILABLE) || defined(__CYGWIN__)
  66. # define CRYPTOPP_ASSERT(exp) { \
  67. if (!(exp)) { \
  68. std::ostringstream oss; \
  69. oss << "Assertion failed: " << __FILE__ << "(" \
  70. << __LINE__ << "): " << __func__ \
  71. << std::endl; \
  72. std::cout << std::flush; \
  73. std::cerr << oss.str(); \
  74. raise(SIGTRAP); \
  75. } \
  76. }
  77. # elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE)
  78. # define CRYPTOPP_ASSERT(exp) { \
  79. if (!(exp)) { \
  80. std::ostringstream oss; \
  81. oss << "Assertion failed: " << __FILE__ << "(" \
  82. << __LINE__ << "): " << __FUNCTION__ \
  83. << std::endl; \
  84. std::cout << std::flush; \
  85. std::cerr << oss.str(); \
  86. if (IsDebuggerPresent()) {DebugBreak();} \
  87. } \
  88. }
  89. # endif // Unix or Windows
  90. #endif // CRYPTOPP_DEBUG
  91. // Remove CRYPTOPP_ASSERT in non-debug builds.
  92. #ifndef CRYPTOPP_ASSERT
  93. # define CRYPTOPP_ASSERT(exp) (void)0
  94. #endif
  95. NAMESPACE_BEGIN(CryptoPP)
  96. // ************** SIGTRAP handler ***************
  97. #if (CRYPTOPP_DEBUG && defined(UNIX_SIGNALS_AVAILABLE)) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
  98. /// \brief Default SIGTRAP handler
  99. /// \details DebugTrapHandler() can be used by a program to install an empty
  100. /// SIGTRAP handler. If present, the handler ensures there is a signal
  101. /// handler in place for <tt>SIGTRAP</tt> raised by
  102. /// <tt>CRYPTOPP_ASSERT</tt>. If <tt>CRYPTOPP_ASSERT</tt> raises
  103. /// <tt>SIGTRAP</tt> <em>without</em> a handler, then one of two things can
  104. /// occur. First, the OS might allow the program to continue. Second, the OS
  105. /// might terminate the program. OS X allows the program to continue, while
  106. /// some Linuxes terminate the program.
  107. /// \details If DebugTrapHandler detects another handler in place, then it will
  108. /// not install a handler. This ensures a debugger can gain control of the
  109. /// <tt>SIGTRAP</tt> signal without contention. It also allows multiple
  110. /// DebugTrapHandler to be created without contentious or unusual behavior.
  111. /// Though multiple DebugTrapHandler can be created, a program should only
  112. /// create one, if needed.
  113. /// \details A DebugTrapHandler is subject to C++ static initialization
  114. /// [dis]order. If you need to install a handler and it must be installed
  115. /// early, then reference the code associated with
  116. /// <tt>CRYPTOPP_INIT_PRIORITY</tt> in cryptlib.cpp and cpu.cpp.
  117. /// \details If you want to ensure <tt>CRYPTOPP_ASSERT</tt> is inert, then
  118. /// <em>do not</em> define <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or
  119. /// <tt>_DEBUG</tt>. Avoiding the defines means <tt>CRYPTOPP_ASSERT</tt>
  120. /// is processed into <tt>((void)0)</tt>.
  121. /// \details The traditional Posix define <tt>NDEBUG</tt> has no effect on
  122. /// <tt>CRYPTOPP_DEBUG</tt>, <tt>CRYPTOPP_ASSERT</tt> or DebugTrapHandler.
  123. /// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and
  124. /// DebugTrapHandler is shown below. The library's test program,
  125. /// <tt>cryptest.exe</tt> (from test.cpp), exercises the structure:
  126. /// <pre>
  127. /// \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
  128. /// const DebugTrapHandler g_dummyHandler;
  129. /// \#endif
  130. ///
  131. /// int main(int argc, char* argv[])
  132. /// {
  133. /// CRYPTOPP_ASSERT(argv != nullptr);
  134. /// ...
  135. /// }
  136. /// </pre>
  137. /// \since Crypto++ 5.6.5
  138. /// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, <A
  139. /// HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
  140. /// <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>
  141. #if defined(CRYPTOPP_DOXYGEN_PROCESSING)
  142. class DebugTrapHandler : public SignalHandler<SIGTRAP, false> { };
  143. #else
  144. typedef SignalHandler<SIGTRAP, false> DebugTrapHandler;
  145. #endif
  146. #endif // Linux, Unix and Documentation
  147. NAMESPACE_END
  148. #endif // CRYPTOPP_TRAP_H