summaryrefslogtreecommitdiff
path: root/trap.h
blob: 1307add4b1df83e89fd9a208abc558e1aa964ff2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// trap.h - written and placed in public domain by Jeffrey Walton.

/// \file trap.h
/// \brief Debugging and diagnostic assertions
/// \details <tt>CRYPTOPP_ASSERT</tt> is the library's debugging and diagnostic
///   assertion. <tt>CRYPTOPP_ASSERT</tt> is enabled by <tt>CRYPTOPP_DEBUG</tt>,
///   <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
/// \details <tt>CRYPTOPP_ASSERT</tt> raises a <tt>SIGTRAP</tt> (Unix) or calls
///   <tt>__debugbreak()</tt> (Windows). <tt>CRYPTOPP_ASSERT</tt> is only in
///   effect when the user requests a debug configuration. Unlike Posix assert,
///   <tt>NDEBUG</tt> (or failure to define it) does not affect the library.
///   The traditional Posix define <tt>NDEBUG</tt> has no effect on
///   <tt>CRYPTOPP_DEBUG</tt> or DebugTrapHandler.
/// \since Crypto++ 5.6.5
/// \sa DebugTrapHandler, <A
///   HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
///   <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>

#ifndef CRYPTOPP_TRAP_H
#define CRYPTOPP_TRAP_H

#include "config.h"

#if defined(CRYPTOPP_DEBUG)
#  include <iostream>
#  include <sstream>
#  if defined(UNIX_SIGNALS_AVAILABLE)
#    include "ossig.h"
#  elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__)
     extern "C" __declspec(dllimport) void __stdcall DebugBreak();
     extern "C" __declspec(dllimport)  int __stdcall IsDebuggerPresent();
#  endif
#endif // CRYPTOPP_DEBUG

// ************** run-time assertion ***************

#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
/// \brief Debugging and diagnostic assertion
/// \details <tt>CRYPTOPP_ASSERT</tt> is the library's debugging and diagnostic
///   assertion. <tt>CRYPTOPP_ASSERT</tt> is enabled by the preprocessor macros
///   <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
/// \details <tt>CRYPTOPP_ASSERT</tt> raises a <tt>SIGTRAP</tt> (Unix) or calls
///   <tt>DebugBreak()</tt> (Windows). <tt>CRYPTOPP_ASSERT</tt> is only in effect
///   when the user explicitly requests a debug configuration.
/// \details If you want to ensure <tt>CRYPTOPP_ASSERT</tt> is inert, then <em>do
///   not</em> define <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or <tt>_DEBUG</tt>.
///   Avoiding the defines means <tt>CRYPTOPP_ASSERT</tt> is preprocessed into an
///   empty string.
/// \details The traditional Posix define <tt>NDEBUG</tt> has no effect on
///   <tt>CRYPTOPP_DEBUG</tt>, <tt>CRYPTOPP_ASSERT</tt> or DebugTrapHandler.
/// \details An example of using CRYPTOPP_ASSERT and DebugTrapHandler is shown
///   below. The library's test program, <tt>cryptest.exe</tt> (from test.cpp),
///   exercises the structure:
///  <pre>
///    \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
///    static const DebugTrapHandler g_dummyHandler;
///    \#endif
///
///    int main(int argc, char* argv[])
///    {
///       CRYPTOPP_ASSERT(argv != nullptr);
///       ...
///    }
///  </pre>
/// \since Crypto++ 5.6.5
/// \sa DebugTrapHandler, SignalHandler, <A
///   HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
///   <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>
#  define CRYPTOPP_ASSERT(exp) { ... }
#endif

#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
#  define CRYPTOPP_ASSERT(exp) {                                  \
    if (!(exp)) {                                                 \
      std::ostringstream oss;                                     \
      oss << "Assertion failed: " << __FILE__ << "("              \
          << __LINE__ << "): " << __func__                        \
          << std::endl;                                           \
      std::cout << std::flush;                                    \
      std::cerr << oss.str();                                     \
      raise(SIGTRAP);                                             \
    }                                                             \
  }
#elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__)
#  define CRYPTOPP_ASSERT(exp) {                                  \
    if (!(exp)) {                                                 \
      std::ostringstream oss;                                     \
      oss << "Assertion failed: " << __FILE__ << "("              \
          << __LINE__ << "): " << __FUNCTION__                    \
          << std::endl;                                           \
      std::cout << std::flush;                                    \
      std::cerr << oss.str();                                     \
      if (IsDebuggerPresent()) {DebugBreak();}                    \
    }                                                             \
  }
#endif // DEBUG and Unix or Windows

// Remove CRYPTOPP_ASSERT in non-debug builds.
//  Can't use CRYPTOPP_UNUSED due to circular dependency
#ifndef CRYPTOPP_ASSERT
#  define CRYPTOPP_ASSERT(exp) (void)0
#endif

NAMESPACE_BEGIN(CryptoPP)

// ************** SIGTRAP handler ***************

#if (CRYPTOPP_DEBUG && defined(UNIX_SIGNALS_AVAILABLE)) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
/// \brief Default SIGTRAP handler
/// \details DebugTrapHandler() can be used by a program to install an empty
///   SIGTRAP handler. If present, the handler ensures there is a signal
///   handler in place for <tt>SIGTRAP</tt> raised by
///   <tt>CRYPTOPP_ASSERT</tt>. If <tt>CRYPTOPP_ASSERT</tt> raises
///   <tt>SIGTRAP</tt> <em>without</em> a handler, then one of two things can
///   occur. First, the OS might allow the program to continue. Second, the OS
///   might terminate the program. OS X allows the program to continue, while
///   some Linuxes terminate the program.
/// \details If DebugTrapHandler detects another handler in place, then it will
///   not install a handler. This ensures a debugger can gain control of the
///   <tt>SIGTRAP</tt> signal without contention. It also allows multiple
///   DebugTrapHandler to be created without contentious or unusual behavior.
///   Though multiple DebugTrapHandler can be created, a program should only
///   create one, if needed.
/// \details A DebugTrapHandler is subject to C++ static initialization
///   [dis]order. If you need to install a handler and it must be installed
///   early, then reference the code associated with
///   <tt>CRYPTOPP_INIT_PRIORITY</tt> in cryptlib.cpp and cpu.cpp.
/// \details If you want to ensure <tt>CRYPTOPP_ASSERT</tt> is inert, then
///   <em>do not</em> define <tt>CRYPTOPP_DEBUG</tt>, <tt>DEBUG</tt> or
///   <tt>_DEBUG</tt>. Avoiding the defines means <tt>CRYPTOPP_ASSERT</tt>
///   is processed into <tt>((void)(exp))</tt>.
/// \details The traditional Posix define <tt>NDEBUG</tt> has no effect on
///   <tt>CRYPTOPP_DEBUG</tt>, <tt>CRYPTOPP_ASSERT</tt> or DebugTrapHandler.
/// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and
///   DebugTrapHandler is shown below. The library's test program,
///   <tt>cryptest.exe</tt> (from test.cpp), exercises the structure:
///  <pre>
///    \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
///    static const DebugTrapHandler g_dummyHandler;
///    \#endif
///
///    int main(int argc, char* argv[])
///    {
///       CRYPTOPP_ASSERT(argv != nullptr);
///       ...
///    }
///  </pre>
/// \since Crypto++ 5.6.5
/// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, <A
///   HREF="http://github.com/weidai11/cryptopp/issues/277">Issue 277</A>,
///   <A HREF="http://seclists.org/oss-sec/2016/q3/520">CVE-2016-7420</A>

#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
class DebugTrapHandler : public SignalHandler<SIGILL, false> { };
#else
typedef SignalHandler<SIGILL, false> DebugTrapHandler;
#endif

#endif  // Linux, Unix and Documentation

NAMESPACE_END

#endif // CRYPTOPP_TRAP_H