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