summaryrefslogtreecommitdiff
path: root/trap.h
blob: a34be810a0ef3a452dddeb3d69cb403479e92fea (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
// 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 \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 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::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::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