// trap.h - written and placed in public domain by Jeffrey Walton. /// \file trap.h /// \brief Debugging and diagnostic assertions /// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic /// assertion. CRYPTOPP_ASSERT is enabled by CRYPTOPP_DEBUG, /// DEBUG or _DEBUG. /// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls /// __debugbreak() (Windows). CRYPTOPP_ASSERT is only in /// effect when the user requests a debug configuration. Unlike Posix assert, /// NDEBUG (or failure to define it) does not affect the library. /// The traditional Posix define NDEBUG has no effect on /// CRYPTOPP_DEBUG or DebugTrapHandler. /// \since Crypto++ 5.6.5 /// \sa DebugTrapHandler, Issue 277, /// CVE-2016-7420 #ifndef CRYPTOPP_TRAP_H #define CRYPTOPP_TRAP_H #include "config.h" #if defined(CRYPTOPP_DEBUG) # include # include # 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 CRYPTOPP_ASSERT is the library's debugging and diagnostic /// assertion. CRYPTOPP_ASSERT is enabled by the preprocessor macros /// CRYPTOPP_DEBUG, DEBUG or _DEBUG. /// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls /// DebugBreak() (Windows). CRYPTOPP_ASSERT is only in effect /// when the user explicitly requests a debug configuration. /// \details If you want to ensure CRYPTOPP_ASSERT is inert, then do /// not define CRYPTOPP_DEBUG, DEBUG or _DEBUG. /// Avoiding the defines means CRYPTOPP_ASSERT is preprocessed into an /// empty string. /// \details The traditional Posix define NDEBUG has no effect on /// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. /// \details An example of using CRYPTOPP_ASSERT and DebugTrapHandler is shown /// below. The library's test program, cryptest.exe (from test.cpp), /// exercises the structure: ///
///    \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
///    static const DebugTrapHandler g_dummyHandler;
///    \#endif
///
///    int main(int argc, char* argv[])
///    {
///       CRYPTOPP_ASSERT(argv != nullptr);
///       ...
///    }
///  
/// \since Crypto++ 5.6.5 /// \sa DebugTrapHandler, SignalHandler, Issue 277, /// CVE-2016-7420 # 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 SIGTRAP raised by /// CRYPTOPP_ASSERT. If CRYPTOPP_ASSERT raises /// SIGTRAP without 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 /// SIGTRAP 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 /// CRYPTOPP_INIT_PRIORITY in cryptlib.cpp and cpu.cpp. /// \details If you want to ensure CRYPTOPP_ASSERT is inert, then /// do not define CRYPTOPP_DEBUG, DEBUG or /// _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT /// is processed into ((void)(exp)). /// \details The traditional Posix define NDEBUG has no effect on /// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. /// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and /// DebugTrapHandler is shown below. The library's test program, /// cryptest.exe (from test.cpp), exercises the structure: ///
///    \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
///    static const DebugTrapHandler g_dummyHandler;
///    \#endif
///
///    int main(int argc, char* argv[])
///    {
///       CRYPTOPP_ASSERT(argv != nullptr);
///       ...
///    }
///  
/// \since Crypto++ 5.6.5 /// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, Issue 277, /// CVE-2016-7420 #if defined(CRYPTOPP_DOXYGEN_PROCESSING) class DebugTrapHandler : public SignalHandler { }; #else typedef SignalHandler DebugTrapHandler; #endif #endif // Linux, Unix and Documentation NAMESPACE_END #endif // CRYPTOPP_TRAP_H