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