This is made to NOT compile ... lines that don't compile are sections I need to check out

exhausted stack. kill vs exit.  using libunwind or backtrace but with symoblizer should be tested
and blogged about(?)
This commit is contained in:
Kjell Hedstrom 2015-08-27 08:02:18 -06:00
parent bc4459d779
commit 671fd01aa1
6 changed files with 118 additions and 55 deletions

View File

@ -28,7 +28,7 @@ IF ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang")
ELSE()
set(PLATFORM_LINK_LIBRIES rt c++abi)
ENDIF()
SET(CMAKE_CXX_FLAGS "-Wall -std=c++11 -pthread -stdlib=libc++ -Wunused -D_GLIBCXX_USE_NANOSLEEP")
SET(CMAKE_CXX_FLAGS "-Wall -std=c++11 -stdlib=libc++ -Wunused -D_GLIBCXX_USE_NANOSLEEP")

View File

@ -16,6 +16,7 @@
#include <string>
#include <chrono>
#include <thread>
#include <exception>
namespace
@ -34,34 +35,34 @@ namespace
}
void RaiseSIGABRT() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
raise(SIGABRT);
LOG(DEBUG) << " trigger exit";
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGFPE() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
LOGF_IF(INFO, (false != true), "Exiting %s SIGFPE", "by");
raise(SIGFPE);
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGSEGV() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
LOG(DEBUG) << "Exit by SIGSEGV";
raise(SIGSEGV);
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGILL() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
LOGF(DEBUG, "Exit by %s", "SIGILL");
raise(SIGILL);
LOG(WARNING) << "Expected to have died by now...";
}
void RAiseSIGTERM() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
LOGF_IF(INFO, (false != true), "Exiting %s SIGFPE", "by");
raise(SIGTERM);
LOG(WARNING) << "Expected to have died by now...";
@ -69,8 +70,7 @@ namespace
int gShouldBeZero = 1;
void DivisionByZero() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
std::cout << "Executing DivisionByZero: gShouldBeZero: " << gShouldBeZero << std::endl;
LOG(DEBUG) << " trigger exit Executing DivisionByZero: gShouldBeZero: " << gShouldBeZero;
LOG(INFO) << "Division by zero is a big no-no";
int value = 3;
auto test = value / gShouldBeZero;
@ -78,14 +78,14 @@ namespace
}
void IllegalPrintf() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
LOG(DEBUG) << "Impending doom due to illeteracy";
LOGF(INFO, "2nd attempt at ILLEGAL PRINTF_SYNTAX %d EXAMPLE. %s %s", "hello", 1);
LOG(WARNING) << "Expected to have died by now...";
}
void OutOfBoundsArrayIndexing() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
std::vector<int> v;
v[0] = 5;
LOG(WARNING) << "Expected to have died by now...";
@ -93,7 +93,7 @@ namespace
void AccessViolation() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
char *ptr = 0;
LOG(INFO) << "Death by access violation is imminent";
*ptr = 0;
@ -101,12 +101,12 @@ namespace
}
void NoExitFunction() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
CHECK(false) << "This function should never be called";
}
void RaiseSIGABRTAndAccessViolation() {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << " trigger exit";
auto f1 = std::async(std::launch::async, &RaiseSIGABRT);
auto f2 = std::async(std::launch::async, &AccessViolation);
@ -114,11 +114,32 @@ namespace
f2.wait();
}
void ThrowInt() {
throw 1233210;
void AccessViolation_x10000() {
LOG(DEBUG) << " trigger exit";
std::vector<std::future<void>> asyncs;
asyncs.reserve(1000);
for (auto idx = 0; idx < 1000; ++idx) {
asyncs.push_back(std::async(std::launch::async, &AccessViolation));
}
for (const auto& a: asyncs) {
a.wait();
}
std::cout << __FUNCTION__ << " unexpected result. AccessViolation x many did not crash and exit the system" << std::endl;
}
void Throw() {
LOG(DEBUG) << " trigger exit";
std::future<int> empty;
empty.get();
// --> 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
}
void FailedCHECK() {
LOG(DEBUG) << " trigger exit";
CHECK(false) << "This is fatal";
}
@ -133,7 +154,8 @@ namespace
void ExecuteDeathFunction(const bool runInNewThread, int fatalChoice) {
std::cout << "Calling :" << __FUNCTION__ << " Line: " << __LINE__ << std::endl << std::flush;
LOG(DEBUG) << "trigger exit";
auto exitFunction = &NoExitFunction;
switch (fatalChoice) {
case 1: exitFunction = &RaiseSIGABRT; break;
@ -146,8 +168,9 @@ namespace
case 8: exitFunction = &OutOfBoundsArrayIndexing; break;
case 9: exitFunction = &AccessViolation; break;
case 10: exitFunction = &RaiseSIGABRTAndAccessViolation; break;
case 11: exitFunction = &ThrowInt; break;
case 11: exitFunction = &Throw; break;
case 12: exitFunction = &FailedCHECK; break;
case 13: exitFunction = &AccessViolation_x10000; break;
default: break;
}
if (runInNewThread) {
@ -203,8 +226,9 @@ namespace
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;
std::cout << "[11] Just throw (in this thread)" << std::endl;
std::cout << "[11] Throw a std::future_error" << std::endl;
std::cout << "[12] Just CHECK(false) (in this thread)" << std::endl;
std::cout << "[13] 1000 Continious crashes with out of counds array indexing" << std::endl;
std::cout << std::flush;
@ -212,7 +236,7 @@ namespace
try {
std::getline(std::cin, option);
choice = std::stoi(option);
if (choice <= 0 || choice > 12) {
if (choice <= 0 || choice > 13) {
std::cout << "Invalid choice: [" << option << "\n\n";
} else {
return choice;
@ -235,6 +259,10 @@ namespace
} // namespace
void breakHere() {
std::ostringstream oss;
oss << "Fatal hook function: " << __FUNCTION__ << ":" << __LINE__ " was called";
oss << " through g3::setFatalPreLoggingHook(). setFatalPreLoggingHook should be called AFTER g3::initializeLogging()" << std::endl;
LOG(DEBUG) << oss.str();
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
__debugbreak();
#endif

View File

@ -23,7 +23,7 @@
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <thread> // temporary to be removed
// Linux/Clang, OSX/Clang, OSX/gcc
#if (defined(__clang__) || defined(__APPLE__))
@ -34,10 +34,51 @@
namespace {
bool shouldDoExit() {
static std::atomic<uint64_t> firstExit{0};
auto const count = firstExit.fetch_add(1, std::memory_order_relaxed);
return (0 == count);
}
void restoreSignalHandler(int signal_number) {
std::cerr << "\n\n" << __FUNCTION__ << " " << signal_number << " threadID: " << std::this_thread::get_id() << std::endl;
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
memset(&action, 0, sizeof (action)); //
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL; // take default action for the signal
sigaction(signal_number, &action, NULL);
#endif
}
// Dump of stack,. then exit through g3log background worker
// ALL thanks to this thread at StackOverflow. Pretty much borrowed from:
// Ref: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
void signalHandler(int signal_number, siginfo_t *info, void *unused_context) {
// Only one signal will be allowed past this point
if (false == shouldDoExit()) {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
Kjell
// Does this make a difference?
// http://man7.org/linux/man-pages/man2/sigaltstack.2.html
stack_t ss;
ss.ss_sp = malloc(SIGSTKSZ);
if (ss.ss_sp == NULL) {
// Handle error -- no error handling at this moment
}
ss.ss_size = SIGSTKSZ;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) {
std::cerr << "\n\n\n\n\nFAILED\n\n\n\n\n" << std::endl;
return;
}
using namespace g3::internal;
{
const auto dump = stackdump();
@ -74,10 +115,11 @@ namespace g3 {
// http://stackoverflow.com/questions/6878546/why-doesnt-parent-process-return-to-the-exact-location-after-handling-signal_number
namespace internal {
bool blockForFatalHandling() {
bool shouldBlockForFatalHandling() {
return true; // For windows we will after fatal processing change it to false
}
/// Generate stackdump. Or in case a stackdump was pre-generated and non-empty just use that one
/// i.e. the latter case is only for Windows and test purposes
std::string stackdump(const char *rawdump) {
@ -180,20 +222,16 @@ namespace g3 {
// Triggered by g3log->g3LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(const LEVELS &level, g3::SignalType fatal_signal_id) {
void exitWithDefaultSignalHandler(const LEVELS &level, g3::SignalType fatal_signal_id) {
const int signal_number = static_cast<int>(fatal_signal_id);
std::cerr << "Exiting due to " << level.text << ", " << signal_number << " " << std::flush;
restoreSignalHandler(signal_number);
std::cerr << "\n\n" << __FUNCTION__ << ":" << __LINE__ << ". Exiting due to " << level.text << ", " << signal_number << " \n\n" << std::flush;
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
memset(&action, 0, sizeof (action)); //
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL; // take default action for the signal
sigaction(signal_number, &action, NULL);
#endif
kill(getpid(), signal_number);
abort(); // should never reach this
TODO kjell ---
what is the difference between kill and exit?
does it have any significance for stack trace
exit(signal_number); //kill(getpid(), signal_number);
}
} // end g3::internal

View File

@ -148,11 +148,9 @@ namespace {
namespace g3 {
namespace internal {
// For windows exceptions this might ONCE be set to false, in case of a
// windows exceptions and not a signal
bool blockForFatalHandling() {
bool shouldBlockForFatalHandling() {
return gBlockForFatal;
}

View File

@ -233,7 +233,7 @@ namespace g3 {
internal::exitWithDefaultSignalHandler(message.get()->_level, message.get()->_signal_id);
}
g_logger_instance->fatal(message);
while (blockForFatalHandling()) {
while (shouldBlockForFatalHandling()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}

View File

@ -11,11 +11,22 @@
#include <csignal>
#include "g3log/loglevels.hpp"
#include "g3log/generated_definitions.hpp"
// kjell. Separera på crashhandler.hpp och crashhanlder_internal.hpp
// implementationsfilen kan vara den samma
namespace g3 {
// PUBLIC API:
/** Install signal handler that catches FATAL C-runtime or OS signals
See the wikipedia site for details http://en.wikipedia.org/wiki/SIGFPE
See the this site for example usage: http://www.tutorialspoint.com/cplusplus/cpp_signal_handling.hpptm
SIGABRT ABORT (ANSI), abnormal termination
SIGFPE Floating point exception (ANSI)
SIGILL ILlegal instruction (ANSI)
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installCrashHandler();
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
typedef unsigned long SignalType;
@ -35,30 +46,18 @@ namespace g3 {
* only in the case of Windows exceptions (not fatal signals)
* are we interested in changing this from false to true to
* help any other exceptions handler work with 'EXCEPTION_CONTINUE_SEARCH'*/
bool blockForFatalHandling();
bool shouldBlockForFatalHandling();
/** \return signal_name Ref: signum.hpp and \ref installSignalHandler
* or for Windows exception name */
std::string exitReasonName(const LEVELS &level, g3::SignalType signal_number);
std::string exitReasonName(const LEVELS& level, g3::SignalType signal_number);
/** return calling thread's stackdump*/
std::string stackdump(const char *dump = nullptr);
std::string stackdump(const char* dump = nullptr);
/** Re-"throw" a fatal signal, previously caught. This will exit the application
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g3log, g3LogWorker after flushing messages to file */
void exitWithDefaultSignalHandler(const LEVELS &level, g3::SignalType signal_number);
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType signal_number);
} // end g3::internal
// PUBLIC API:
/** Install signal handler that catches FATAL C-runtime or OS signals
See the wikipedia site for details http://en.wikipedia.org/wiki/SIGFPE
See the this site for example usage: http://www.tutorialspoint.com/cplusplus/cpp_signal_handling.hpptm
SIGABRT ABORT (ANSI), abnormal termination
SIGFPE Floating point exception (ANSI)
SIGILL ILlegal instruction (ANSI)
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installCrashHandler();
}
} // g3