2014-12-12 16:44:17 +01:00
/** ==========================================================================
* 2014 by KjellKod . cc . This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties . This code is yours to share , use and modify with no
* strings attached and no restrictions or obligations .
2014-12-12 10:05:51 +01:00
*
2014-12-12 16:44:17 +01:00
* For more information see g3log / LICENSE or refer refer to http : //unlicense.org
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2015-07-20 07:10:56 +02:00
# include <g3log/g3log.hpp>
# include <g3log/logworker.hpp>
2015-07-16 09:55:23 +02:00
2014-12-12 16:44:17 +01:00
# include <cctype>
2023-12-01 00:17:45 +01:00
# include <chrono>
# include <exception>
2014-12-12 16:44:17 +01:00
# include <future>
2023-12-01 00:17:45 +01:00
# include <iostream>
2014-12-12 16:44:17 +01:00
# include <string>
2014-12-12 10:05:51 +01:00
# include <thread>
2023-12-01 00:17:45 +01:00
# include <vector>
2014-12-12 16:44:17 +01:00
2015-09-01 07:45:47 +02:00
# ifndef _MSC_VER
# define NOEXCEPT noexcept
# else
# define NOEXCEPT throw()
# endif
2014-12-12 16:44:17 +01:00
2023-12-01 00:17:45 +01:00
namespace {
2014-12-12 16:44:17 +01:00
# if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
2015-07-16 09:55:23 +02:00
const std : : string path_to_log_file = " ./ " ;
2014-12-12 16:44:17 +01:00
# else
2015-07-16 09:55:23 +02:00
const std : : string path_to_log_file = " /tmp/ " ;
2014-12-12 16:44:17 +01:00
# endif
2023-12-01 00:17:45 +01:00
void ToLower ( std : : string & str ) {
for ( auto & character : str ) {
2015-07-16 09:55:23 +02:00
character = std : : tolower ( character ) ;
}
2014-12-12 10:05:51 +01:00
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RaiseSIGABRT ( ) {
raise ( SIGABRT ) ;
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RaiseSIGFPE ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
LOGF_IF ( INFO , ( false ! = true ) , " Exiting %s SIGFPE " , " by " ) ;
raise ( SIGFPE ) ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RaiseSIGSEGV ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
LOG ( G3LOG_DEBUG ) < < " Exit by SIGSEGV " ;
2015-07-16 09:55:23 +02:00
raise ( SIGSEGV ) ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RaiseSIGILL ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
LOGF ( G3LOG_DEBUG , " Exit by %s " , " SIGILL " ) ;
2015-07-16 09:55:23 +02:00
raise ( SIGILL ) ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RAiseSIGTERM ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
LOGF_IF ( INFO , ( false ! = true ) , " Exiting %s SIGFPE " , " by " ) ;
raise ( SIGTERM ) ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
int gShouldBeZero = 1 ;
void DivisionByZero ( ) {
2023-12-01 00:17:45 +01:00
LOG ( G3LOG_DEBUG ) < < " trigger exit Executing DivisionByZero: gShouldBeZero: " < < gShouldBeZero ;
2015-07-16 09:55:23 +02:00
LOG ( INFO ) < < " Division by zero is a big no-no " ;
int value = 3 ;
auto test = value / gShouldBeZero ;
LOG ( WARNING ) < < " Expected to have died by now..., test value: " < < test ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void IllegalPrintf ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
LOG ( G3LOG_DEBUG ) < < " Impending doom due to illeteracy " ;
2015-07-16 09:55:23 +02:00
LOGF ( INFO , " 2nd attempt at ILLEGAL PRINTF_SYNTAX %d EXAMPLE. %s %s " , " hello " , 1 ) ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void OutOfBoundsArrayIndexing ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
std : : vector < int > v ;
v [ 0 ] = 5 ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void AccessViolation ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2023-12-01 00:17:45 +01:00
char * ptr = 0 ;
2015-07-16 09:55:23 +02:00
LOG ( INFO ) < < " Death by access violation is imminent " ;
* ptr = 0 ;
LOG ( WARNING ) < < " Expected to have died by now... " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void NoExitFunction ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
CHECK ( false ) < < " This function should never be called " ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void RaiseSIGABRTAndAccessViolation ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-02-02 08:31:43 +01:00
2015-07-16 09:55:23 +02:00
auto f1 = std : : async ( std : : launch : : async , & RaiseSIGABRT ) ;
auto f2 = std : : async ( std : : launch : : async , & AccessViolation ) ;
f1 . wait ( ) ;
f2 . wait ( ) ;
}
2015-02-02 08:31:43 +01:00
2023-12-01 00:17:45 +01:00
using deathfunc = void ( * ) ( void ) ;
2015-09-01 07:45:47 +02:00
void Death_x10000 ( deathfunc func , std : : string funcname ) NOEXCEPT {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-08-27 16:02:18 +02:00
std : : vector < std : : future < void > > asyncs ;
2015-09-01 06:30:48 +02:00
asyncs . reserve ( 10000 ) ;
for ( auto idx = 0 ; idx < 10000 ; + + idx ) {
asyncs . push_back ( std : : async ( std : : launch : : async , func ) ) ;
2015-08-27 16:02:18 +02:00
}
2015-09-01 06:30:48 +02:00
for ( const auto & a : asyncs ) {
2015-08-27 16:02:18 +02:00
a . wait ( ) ;
}
2015-09-01 06:30:48 +02:00
std : : cout < < __FUNCTION__ < < " unexpected result. Death by " < < funcname < < " did not crash and exit the system " < < std : : endl ;
2015-08-27 16:02:18 +02:00
}
2015-09-01 07:45:47 +02:00
void Throw ( ) NOEXCEPT {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-08-27 16:02:18 +02:00
std : : future < int > empty ;
2023-12-01 00:17:45 +01:00
empty . get ( ) ;
2015-08-27 16:02:18 +02:00
// --> thows future_error http://en.cppreference.com/w/cpp/thread/future_error
// example of std::exceptions can be found here: http://en.cppreference.com/w/cpp/error/exception
2015-07-16 09:55:23 +02:00
}
2015-02-23 07:31:17 +01:00
2015-09-01 07:45:47 +02:00
void SegFaultAttempt_x10000 ( ) NOEXCEPT {
2023-12-01 00:17:45 +01:00
deathfunc f = [ ] {
char * ptr = 0 ;
* ptr = 1 ;
} ;
2015-09-01 07:07:25 +02:00
Death_x10000 ( f , " throw uncaught exception... and then some sigsegv calls " ) ;
2015-09-01 06:30:48 +02:00
}
void AccessViolation_x10000 ( ) {
Death_x10000 ( & AccessViolation , " AccessViolation " ) ;
2015-07-16 09:55:23 +02:00
}
2015-02-23 07:31:17 +01:00
2015-07-16 09:55:23 +02:00
void FailedCHECK ( ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-07-16 09:55:23 +02:00
CHECK ( false ) < < " This is fatal " ;
}
2015-02-02 08:31:43 +01:00
2015-07-16 09:55:23 +02:00
void CallActualExitFunction ( std : : function < void ( ) > fatal_function ) {
fatal_function ( ) ;
}
2015-02-02 08:31:43 +01:00
2015-07-16 09:55:23 +02:00
void CallExitFunction ( std : : function < void ( ) > fatal_function ) {
CallActualExitFunction ( fatal_function ) ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void ExecuteDeathFunction ( const bool runInNewThread , int fatalChoice ) {
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < " trigger exit " ;
2015-08-27 16:02:18 +02:00
2015-07-16 09:55:23 +02:00
auto exitFunction = & NoExitFunction ;
switch ( fatalChoice ) {
2023-12-01 00:17:45 +01:00
case 1 :
exitFunction = & RaiseSIGABRT ;
break ;
case 2 :
exitFunction = & RaiseSIGFPE ;
break ;
case 3 :
exitFunction = & RaiseSIGSEGV ;
break ;
case 4 :
exitFunction = & RaiseSIGILL ;
break ;
case 5 :
exitFunction = & RAiseSIGTERM ;
break ;
case 6 :
exitFunction = & DivisionByZero ;
gShouldBeZero = 0 ;
DivisionByZero ( ) ;
break ;
case 7 :
exitFunction = & IllegalPrintf ;
break ;
case 8 :
exitFunction = & OutOfBoundsArrayIndexing ;
break ;
case 9 :
exitFunction = & AccessViolation ;
break ;
case 10 :
exitFunction = & RaiseSIGABRTAndAccessViolation ;
break ;
case 11 :
exitFunction = & Throw ;
break ;
case 12 :
exitFunction = & FailedCHECK ;
break ;
case 13 :
exitFunction = & AccessViolation_x10000 ;
break ;
case 14 :
exitFunction = & SegFaultAttempt_x10000 ;
break ;
default :
break ;
2015-07-16 09:55:23 +02:00
}
if ( runInNewThread ) {
auto dieInNearFuture = std : : async ( std : : launch : : async , CallExitFunction , exitFunction ) ;
dieInNearFuture . wait ( ) ;
} else {
CallExitFunction ( exitFunction ) ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
std : : string unexpected = " Expected to exit by FATAL event. That did not happen (printf choice in Windows?). " ;
2023-12-01 00:17:45 +01:00
unexpected . append ( " Choice was: " ) . append ( std : : to_string ( fatalChoice ) ) . append ( " , async?: " ) . append ( std : : to_string ( runInNewThread ) ) . append ( " \n \n ***** TEST WILL RUN AGAIN ***** \n \n " ) ;
2014-12-12 16:44:17 +01:00
2023-12-01 00:17:45 +01:00
std : : cerr < < unexpected < < std : : endl ;
2015-07-16 09:55:23 +02:00
LOG ( WARNING ) < < unexpected ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
bool AskForAsyncDeath ( ) {
std : : string option ;
while ( true ) {
option . clear ( ) ;
std : : cout < < " Do you want to run the test in a separate thread? [yes/no] " < < std : : endl ;
std : : getline ( std : : cin , option ) ;
ToLower ( option ) ;
if ( ( " yes " ! = option ) & & ( " no " ! = option ) ) {
std : : cout < < " \n Invalid value: [ " < < option < < " ] \n \n \n " ;
} else {
break ;
}
2014-12-12 16:44:17 +01:00
}
2015-07-16 09:55:23 +02:00
return ( " yes " = = option ) ;
2014-12-12 16:44:17 +01:00
}
2015-07-16 09:55:23 +02:00
int ChoiceOfFatalExit ( ) {
std : : string option ;
int choice = { 0 } ;
while ( true ) {
std : : cout < < " \n \n \n \n Choose your exit " < < std : : endl ;
std : : cout < < " By throwing an fatal signal " < < std : : endl ;
std : : cout < < " or By executing a fatal code snippet " < < std : : endl ;
std : : cout < < " [1] Signal SIGABRT " < < std : : endl ;
std : : cout < < " [2] Signal SIGFPE " < < std : : endl ;
std : : cout < < " [3] Signal SIGSEGV " < < std : : endl ;
std : : cout < < " [4] Signal IGILL " < < std : : endl ;
std : : cout < < " [5] Signal SIGTERM " < < std : : endl ;
std : : cout < < " [6] Division By Zero " < < std : : endl ;
std : : cout < < " [7] Illegal printf " < < std : : endl ;
std : : cout < < " [8] Out of bounds array indexing " < < std : : endl ;
std : : cout < < " [9] Access violation " < < std : : endl ;
std : : cout < < " [10] Rasing SIGABRT + Access Violation in two separate threads " < < std : : endl ;
2015-08-27 16:02:18 +02:00
std : : cout < < " [11] Throw a std::future_error " < < std : : endl ;
2015-07-16 09:55:23 +02:00
std : : cout < < " [12] Just CHECK(false) (in this thread) " < < std : : endl ;
2015-09-01 06:30:48 +02:00
std : : cout < < " [13] 10,000 Continious crashes with out of bounds array indexing " < < std : : endl ;
std : : cout < < " [14] 10,000 Continious crashes with segmentation fault attempts " < < std : : endl ;
2015-07-16 09:55:23 +02:00
std : : cout < < std : : flush ;
try {
std : : getline ( std : : cin , option ) ;
choice = std : : stoi ( option ) ;
2015-09-01 06:30:48 +02:00
if ( choice < = 0 | | choice > 14 ) {
2015-07-16 09:55:23 +02:00
std : : cout < < " Invalid choice: [ " < < option < < " \n \n " ;
2023-12-01 00:17:45 +01:00
} else {
2015-07-16 09:55:23 +02:00
return choice ;
}
} catch ( . . . ) {
2014-12-12 10:05:51 +01:00
std : : cout < < " Invalid choice: [ " < < option < < " \n \n " ;
}
2014-12-12 16:44:17 +01:00
}
2014-12-12 10:05:51 +01:00
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void ForwardChoiceForFatalExit ( bool runInNewThread , int fatalChoice ) {
ExecuteDeathFunction ( runInNewThread , fatalChoice ) ;
}
2014-12-12 16:44:17 +01:00
2015-07-16 09:55:23 +02:00
void ChooseFatalExit ( ) {
const bool runInNewThread = AskForAsyncDeath ( ) ;
const int exitChoice = ChoiceOfFatalExit ( ) ;
ForwardChoiceForFatalExit ( runInNewThread , exitChoice ) ;
}
2023-12-01 00:17:45 +01:00
} // namespace
2014-12-12 16:44:17 +01:00
2015-03-02 09:14:03 +01:00
void breakHere ( ) {
2015-08-19 18:08:41 +02:00
std : : ostringstream oss ;
2023-12-01 00:17:45 +01:00
oss < < " Fatal hook function: " < < __FUNCTION__ < < " : " < < __LINE__ < < " was called " ;
2015-08-27 16:02:18 +02:00
oss < < " through g3::setFatalPreLoggingHook(). setFatalPreLoggingHook should be called AFTER g3::initializeLogging() " < < std : : endl ;
2017-05-09 18:26:48 +02:00
LOG ( G3LOG_DEBUG ) < < oss . str ( ) ;
2015-07-16 09:55:23 +02:00
# if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
__debugbreak ( ) ;
# endif
2015-03-02 09:14:03 +01:00
}
2023-12-01 00:17:45 +01:00
int main ( int argc , char * * argv ) {
2015-08-19 18:08:41 +02:00
auto worker = g3 : : LogWorker : : createLogWorker ( ) ;
2023-12-01 00:17:45 +01:00
auto handle = worker - > addDefaultLogger ( argv [ 0 ] , path_to_log_file ) ;
2015-08-19 18:08:41 +02:00
g3 : : initializeLogging ( worker . get ( ) ) ;
2015-08-19 18:19:55 +02:00
g3 : : setFatalPreLoggingHook ( & breakHere ) ;
2015-08-19 18:08:41 +02:00
std : : future < std : : string > log_file_name = handle - > call ( & g3 : : FileSink : : fileName ) ;
2015-09-01 07:07:25 +02:00
2014-12-12 10:05:51 +01:00
std : : cout < < " **** G3LOG FATAL EXAMPLE *** \n \n "
< < " Choose your type of fatal exit, then "
< < " read the generated log and backtrace. \n "
2023-12-01 00:17:45 +01:00
< < " The logfile is generated at: [ " < < log_file_name . get ( ) < < " ] \n \n "
< < std : : endl ;
2014-12-12 10:05:51 +01:00
2017-05-09 18:26:48 +02:00
LOGF ( G3LOG_DEBUG , " Fatal exit example starts now, it's as easy as %d " , 123 ) ;
2014-12-12 10:05:51 +01:00
LOG ( INFO ) < < " Feel free to read the source code also in g3log/example/main_fatal_choice.cpp " ;
while ( true ) {
ChooseFatalExit ( ) ;
}
LOG ( WARNING ) < < " Expected to exit by fatal event, this code line should never be reached " ;
CHECK ( false ) < < " Forced death " ;
return 0 ;
2014-12-12 16:44:17 +01:00
}