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