// trap.h - written and placed in public domain by Jeffrey Walton. // Copyright assigned to Crypto++ project //! \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 CRYPTOPP_DEBUG # include # include # if defined(CRYPTOPP_BSD_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE) # include "ossig.h" # elif defined(CRYPTOPP_WIN32_AVAILABLE) # if (_MSC_VER >= 1400) # include # endif # 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 explictly 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 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 CRYPTOPP_DEBUG && (defined(CRYPTOPP_BSD_AVAILABLE) || defined(CRYPTOPP_UNIX_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 CRYPTOPP_DEBUG && (defined(CRYPTOPP_BSD_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE)) # define CRYPTOPP_ASSERT(exp) { \ if (!(exp)) { \ std::ostringstream oss; \ oss << "Assertion failed: " << (char*)(__FILE__) << "(" \ << (int)(__LINE__) << "): " << (char*)(__func__) \ << std::endl; \ std::cerr << oss.str(); \ raise(SIGTRAP); \ } \ } #elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE) # define CRYPTOPP_ASSERT(exp) { \ if (!(exp)) { \ std::ostringstream oss; \ oss << "Assertion failed: " << (char*)(__FILE__) << "(" \ << (int)(__LINE__) << "): " << (char*)(__FUNCTION__) \ << std::endl; \ std::cerr << oss.str(); \ __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)(exp)) #endif NAMESPACE_BEGIN(CryptoPP) // ************** SIGTRAP handler *************** #if (CRYPTOPP_DEBUG && (defined(CRYPTOPP_BSD_AVAILABLE) || defined(CRYPTOPP_UNIX_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 muliple 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 CRYPTOPP_DEBUG && (defined(CRYPTOPP_BSD_AVAILABLE) || defined(CRYPTOPP_UNIX_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