mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
As it turns out, the exception parser was calling exit() to abort the program. Unfortunately, exit() performs the cleanup of global static variables. Because an error may occur when those global variables are still in use by other threads, or during their cleanup, calling exit() at the exception parser led to undefined behavior (most often, crashes that would mask the original error). Note that the exception parser is not yet fully safe against crashes while reporting errors: it uses printf and other non-reentrant functions. This will require more effort to cleanup.
681 lines
19 KiB
C++
681 lines
19 KiB
C++
#include "ExceptionParser.h"
|
|
|
|
#include "../Program/ProgramConfig.h"
|
|
#include "../logfacility.h"
|
|
#include "../threadhelp.h"
|
|
#include "pol_global_config.h"
|
|
#include <format/format.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
|
|
#ifndef WINDOWS
|
|
#include <arpa/inet.h>
|
|
#include <cxxabi.h>
|
|
#include <execinfo.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#define SOCKET int
|
|
#else
|
|
#include "../Header_Windows.h"
|
|
#endif
|
|
|
|
#define MAX_STACK_TRACE_DEPTH 200
|
|
#define MAX_STACK_TRACE_STEP_LENGTH 512
|
|
|
|
namespace Pol
|
|
{
|
|
namespace Clib
|
|
{
|
|
using namespace std;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ExceptionParser::m_programAbortReporting = false;
|
|
std::string ExceptionParser::m_programAbortReportingServer = "";
|
|
std::string ExceptionParser::m_programAbortReportingUrl = "";
|
|
std::string ExceptionParser::m_programAbortReportingReporter = "";
|
|
std::string ExceptionParser::m_programStart = Pol::Clib::Logging::LogSink::getTimeStamp();
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace
|
|
{
|
|
void getSignalDescription( int signal, string& signalName, string& signalDescription )
|
|
{
|
|
switch ( signal )
|
|
{
|
|
case 1:
|
|
signalName = "SIGHUP";
|
|
signalDescription = "hangup detected on controlling terminal or death of controlling process";
|
|
break;
|
|
case 2:
|
|
signalName = "SIGINT";
|
|
signalDescription = "interrupt from keyboard";
|
|
break;
|
|
case 3:
|
|
signalName = "SIGQUIT";
|
|
signalDescription = "quit from keyboard";
|
|
break;
|
|
case 4:
|
|
signalName = "SIGILL";
|
|
signalDescription = "illegal Instruction";
|
|
break;
|
|
case 6:
|
|
signalName = "SIGABRT";
|
|
signalDescription = "abort signal from abort()";
|
|
break;
|
|
case 8:
|
|
signalName = "SIGFPE";
|
|
signalDescription = "floating point exception";
|
|
break;
|
|
case 9:
|
|
signalName = "SIGKILL";
|
|
signalDescription = "kill signal";
|
|
break;
|
|
case 10:
|
|
signalName = "SIGBUS";
|
|
signalDescription = "bus error";
|
|
break;
|
|
case 11:
|
|
signalName = "SIGSEGV";
|
|
signalDescription = "invalid memory reference";
|
|
break;
|
|
case 12:
|
|
signalName = "SIGSYS";
|
|
signalDescription = "bad argument to system call";
|
|
break;
|
|
case 13:
|
|
signalName = "SIGPIPE";
|
|
signalDescription = "broken pipe: write to pipe with no readers";
|
|
break;
|
|
case 14:
|
|
signalName = "SIGALRM";
|
|
signalDescription = "timer signal from alarm()";
|
|
break;
|
|
case 15:
|
|
signalName = "SIGTERM";
|
|
signalDescription = "termination signal";
|
|
break;
|
|
case 18:
|
|
signalName = "SIGCONT";
|
|
signalDescription = "continue signal from tty";
|
|
break;
|
|
case 19:
|
|
signalName = "SIGSTOP";
|
|
signalDescription = "stop signal from tty";
|
|
break;
|
|
case 20:
|
|
signalName = "SIGTSTP";
|
|
signalDescription = "stop signal from user (keyboard)";
|
|
break;
|
|
case 16:
|
|
case 30:
|
|
signalName = "SIGUSR1";
|
|
signalDescription = "user-defined signal 1";
|
|
break;
|
|
case 17:
|
|
case 31:
|
|
signalName = "SIGUSR2";
|
|
signalDescription = "user-defined signal 2";
|
|
break;
|
|
default:
|
|
signalName = "unsupported signal";
|
|
signalDescription = "unsupported signal occurred";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void logExceptionSignal( int signal )
|
|
{
|
|
string signalName;
|
|
string signalDescription;
|
|
|
|
getSignalDescription( signal, signalName, signalDescription );
|
|
printf( "Signal \"%s\"(%d: %s) detected.\n", signalName.c_str(), signal,
|
|
signalDescription.c_str() );
|
|
}
|
|
|
|
string getCompilerVersion()
|
|
{
|
|
#ifdef LINUX
|
|
char result[256];
|
|
#ifdef __clang__
|
|
sprintf( result, "clang %d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__ );
|
|
#else
|
|
sprintf( result, "gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );
|
|
#endif
|
|
#endif
|
|
#ifdef WINDOWS
|
|
string result;
|
|
switch ( _MSC_VER )
|
|
{
|
|
case 1900:
|
|
result = "MSVC++ 14.0 (Visual Studio 2015)";
|
|
break;
|
|
case 1800:
|
|
result = "MSVC++ 12.0 (Visual Studio 2013)";
|
|
break;
|
|
case 1700:
|
|
result = "MSVC++ 11.0 (Visual Studio 2012)";
|
|
break;
|
|
case 1600:
|
|
result = "MSVC++ 10.0 (Visual Studio 2010)";
|
|
break;
|
|
case 1500:
|
|
result = "MSVC++ 9.0 (Visual Studio 2008)";
|
|
break;
|
|
case 1400:
|
|
result = "MSVC++ 8.0 (Visual Studio 2005)";
|
|
break;
|
|
case 1310:
|
|
result = "MSVC++ 7.1 (Visual Studio 2003)";
|
|
break;
|
|
case 1300:
|
|
result = "MSVC++ 7.0";
|
|
break;
|
|
case 1200:
|
|
result = "MSVC++ 6.0";
|
|
break;
|
|
case 1100:
|
|
result = "MSVC++ 5.0";
|
|
break;
|
|
default:
|
|
#if ( _MSC_VER > 1800 )
|
|
result = "MSVC++ newer than version 12.0";
|
|
#elif ( _MSC_VER < 1100 )
|
|
result = "MSVC++ older than version 5.0";
|
|
#else
|
|
result = "MSVC++ (some unsupported version)";
|
|
#endif
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
void doHttpPOST( const string& host, const string& url, const string& content )
|
|
{
|
|
#define MAXLINE 4096
|
|
char request[MAXLINE + 1];
|
|
SOCKET socketFD;
|
|
char targetIP[INET6_ADDRSTRLEN];
|
|
|
|
/**
|
|
* prepare the request
|
|
*/
|
|
#ifdef _MSC_VER
|
|
_snprintf(
|
|
#else
|
|
snprintf(
|
|
#endif
|
|
request, MAXLINE,
|
|
"POST %s HTTP/1.0\r\n"
|
|
"Host: %s\r\n"
|
|
"Content-Type: application/x-www-form-urlencoded\r\n"
|
|
"User-Agent: POL in-app abort reporting system, %s\r\n"
|
|
"Content-length: %d\r\n\r\n"
|
|
"%s",
|
|
url.c_str(), host.c_str(), POL_VERSION_ID, (int)content.size(), content.c_str() );
|
|
|
|
/**
|
|
* DNS lookup if needed
|
|
*/
|
|
struct addrinfo* serverAddr;
|
|
struct addrinfo hints;
|
|
memset( &hints, 0, sizeof hints );
|
|
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
|
|
hints.ai_flags = AI_ADDRCONFIG;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
int res = getaddrinfo( host.c_str(), "http", &hints, &serverAddr );
|
|
if ( res != 0 )
|
|
{
|
|
fprintf( stderr, "getaddrinfo() failed for \"%s\" due to \"%s\"(code: %d)\n", host.c_str(),
|
|
gai_strerror( res ), res );
|
|
std::_Exit( 1 );
|
|
}
|
|
|
|
switch ( serverAddr->ai_addr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
if ( inet_ntop( AF_INET, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
|
|
INET_ADDRSTRLEN ) == nullptr )
|
|
std::_Exit( 1 );
|
|
break;
|
|
|
|
case AF_INET6:
|
|
if ( inet_ntop( AF_INET6, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
|
|
INET6_ADDRSTRLEN ) == nullptr )
|
|
std::_Exit( 1 );
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "Unknown address family found for %s\n", host.c_str() );
|
|
std::_Exit( 1 );
|
|
}
|
|
|
|
// create the socket
|
|
socketFD = socket( serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol );
|
|
|
|
/**
|
|
* connect to the bug tracking server
|
|
*/
|
|
if ( ( res = connect( socketFD, serverAddr->ai_addr, (int)serverAddr->ai_addrlen ) ) != 0 )
|
|
{
|
|
fprintf( stderr, "connect() failed for server \"%s\"(IP: %s) due \"%s\"(%d)\n", host.c_str(),
|
|
targetIP, strerror( errno ), errno );
|
|
std::_Exit( 1 );
|
|
}
|
|
|
|
freeaddrinfo( serverAddr ); // not needed anymore
|
|
|
|
/**
|
|
* send the request
|
|
*/
|
|
#ifndef _WIN32
|
|
send( socketFD, request, strlen( request ), MSG_NOSIGNAL );
|
|
#else
|
|
send( socketFD, request, (int)strlen( request ), 0 );
|
|
#endif
|
|
printf( "Abort report was sent to %s%s (IP: %s)\n", host.c_str(), url.c_str(), targetIP );
|
|
|
|
/**
|
|
* wait for some answers and print them on the screen
|
|
*/
|
|
ssize_t readBytes;
|
|
char answer[MAXLINE + 1];
|
|
|
|
#ifndef _WIN32
|
|
while ( ( readBytes = recv( socketFD, answer, MAXLINE, MSG_NOSIGNAL ) ) > 0 )
|
|
{
|
|
#else
|
|
while ( ( readBytes = recv( socketFD, answer, MAXLINE, 0 ) ) > 0 )
|
|
{
|
|
#endif
|
|
answer[readBytes] = '\0';
|
|
printf( "Answer from bug tracking server:\n%s\n", answer );
|
|
// skip the received answer and proceed
|
|
}
|
|
|
|
// close the socket to the bug tracking server
|
|
#ifndef _WIN32
|
|
close( socketFD );
|
|
#else
|
|
closesocket( socketFD );
|
|
#endif
|
|
}
|
|
} // namespace
|
|
|
|
void ExceptionParser::reportProgramAbort( const string& stackTrace, const string& reason )
|
|
{
|
|
/**
|
|
* set some default values if the abort occurs too early and pol.cfg wasn't parsed yet
|
|
*/
|
|
string host = "polserver.com";
|
|
string url = "/pol/report_program_abort.php";
|
|
if ( ( m_programAbortReportingServer.c_str() != nullptr ) &&
|
|
( m_programAbortReportingServer != "" ) )
|
|
{
|
|
host = m_programAbortReportingServer;
|
|
if ( m_programAbortReportingUrl.c_str() != nullptr )
|
|
url = m_programAbortReportingUrl;
|
|
}
|
|
|
|
// create the abort description for the subsequent POST request
|
|
string content = "email=" + m_programAbortReportingReporter +
|
|
"&"
|
|
"bin=" +
|
|
PROG_CONFIG::programName() +
|
|
"&"
|
|
"start_time=" +
|
|
m_programStart +
|
|
"&"
|
|
"abort_time=" +
|
|
Pol::Clib::Logging::LogSink::getTimeStamp() +
|
|
"&"
|
|
"reason=" +
|
|
reason +
|
|
"&"
|
|
"trace=" +
|
|
stackTrace +
|
|
"&"
|
|
"comp=" +
|
|
getCompilerVersion() +
|
|
"&"
|
|
"comp_time=" +
|
|
ProgramConfig::build_datetime() +
|
|
"&"
|
|
"build_target=" +
|
|
ProgramConfig::build_target() +
|
|
"&"
|
|
"build_revision=" POL_VERSION_ID
|
|
"&"
|
|
"misc=";
|
|
|
|
// execute the POST request
|
|
doHttpPOST( host, url, content );
|
|
}
|
|
|
|
void ExceptionParser::handleExceptionSignal( int signal )
|
|
{
|
|
switch ( signal )
|
|
{
|
|
case SIGILL:
|
|
case SIGFPE:
|
|
case SIGSEGV:
|
|
case SIGTERM:
|
|
case SIGABRT:
|
|
{
|
|
/**
|
|
* inform the user about the program abort
|
|
*/
|
|
printf(
|
|
"########################################################################################"
|
|
"\n" );
|
|
if ( m_programAbortReporting )
|
|
printf( "POL will exit now. The following will be sent to the POL developers:\n\n" );
|
|
else
|
|
printf(
|
|
"POL will exit now. Please, post the following to the forum: "
|
|
"http://forums.polserver.com/.\n" );
|
|
string tStackTrace = ExceptionParser::getTrace();
|
|
printf( "%s", tStackTrace.c_str() );
|
|
printf( "Admin contact: %s\n", m_programAbortReportingReporter.c_str() );
|
|
printf( "Executable: %s\n", PROG_CONFIG::programName().c_str() );
|
|
printf( "Start time: %s\n", m_programStart.c_str() );
|
|
printf( "Current time: %s\n", Pol::Clib::Logging::LogSink::getTimeStamp().c_str() );
|
|
printf( "\n" );
|
|
printf( "Stack trace:\n%s", tStackTrace.c_str() );
|
|
printf( "\n" );
|
|
printf( "Compiler: %s\n", getCompilerVersion().c_str() );
|
|
printf( "Compile time: %s\n", ProgramConfig::build_datetime().c_str() );
|
|
printf( "Build target: %s\n", ProgramConfig::build_target().c_str() );
|
|
printf( "Build revision: %s\n", POL_VERSION_ID );
|
|
#ifndef _WIN32
|
|
printf( "GNU C library (compile time): %d.%d\n", __GLIBC__, __GLIBC_MINOR__ );
|
|
#endif
|
|
printf( "\n" );
|
|
printf(
|
|
"########################################################################################"
|
|
"\n" );
|
|
fflush( stdout );
|
|
|
|
/**
|
|
* use the program abort reporting system
|
|
*/
|
|
if ( m_programAbortReporting )
|
|
{
|
|
string signalName;
|
|
string signalDescription;
|
|
|
|
getSignalDescription( signal, signalName, signalDescription );
|
|
ExceptionParser::reportProgramAbort(
|
|
tStackTrace, "CRASH caused by signal " + signalName + " (" + signalDescription + ")" );
|
|
}
|
|
|
|
// finally, go to hell
|
|
std::_Exit( 1 );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
ExceptionParser::ExceptionParser() {}
|
|
|
|
ExceptionParser::~ExceptionParser() {}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _WIN32
|
|
string ExceptionParser::getTrace()
|
|
{
|
|
string result;
|
|
|
|
void* stackTrace[MAX_STACK_TRACE_DEPTH];
|
|
int stackTraceSize;
|
|
char** stackTraceList;
|
|
int stackTraceStep = 0;
|
|
char* stringBuf = (char*)malloc( MAX_STACK_TRACE_STEP_LENGTH );
|
|
|
|
stackTraceSize = backtrace( stackTrace, MAX_STACK_TRACE_DEPTH );
|
|
stackTraceList = backtrace_symbols( stackTrace, stackTraceSize );
|
|
|
|
size_t funcNameSize = 256;
|
|
char* funcnName = (char*)malloc( funcNameSize );
|
|
|
|
// iterate over all entries and do the demangling
|
|
for ( int i = 0; i < stackTraceSize; i++ )
|
|
{
|
|
// get the pointers to the name, offset and end of offset
|
|
char* beginFuncName = nullptr;
|
|
char* beginFuncOffset = nullptr;
|
|
char* endFuncOffset = nullptr;
|
|
char* beginBinaryName = stackTraceList[i];
|
|
char* beginBinaryOffset = nullptr;
|
|
char* endBinaryOffset = nullptr;
|
|
for ( char* entryPointer = stackTraceList[i]; *entryPointer; ++entryPointer )
|
|
{
|
|
if ( *entryPointer == '(' )
|
|
{
|
|
beginFuncName = entryPointer;
|
|
}
|
|
else if ( *entryPointer == '+' )
|
|
{
|
|
beginFuncOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == ')' && beginFuncOffset )
|
|
{
|
|
endFuncOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == '[' )
|
|
{
|
|
beginBinaryOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == ']' && beginBinaryOffset )
|
|
{
|
|
endBinaryOffset = entryPointer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set the default value for the output line
|
|
sprintf( stringBuf, "\n" );
|
|
|
|
bool parse_succeeded = beginFuncName && beginFuncOffset && endFuncOffset && beginBinaryOffset &&
|
|
endBinaryOffset && beginFuncName < beginFuncOffset;
|
|
|
|
// get the detailed values for the output line if available
|
|
if ( parse_succeeded )
|
|
{
|
|
// terminate the C strings
|
|
*beginFuncName++ = '\0';
|
|
*beginFuncOffset++ = '\0';
|
|
*endFuncOffset = '\0';
|
|
*beginBinaryOffset++ = '\0';
|
|
*endBinaryOffset = '\0';
|
|
|
|
int res;
|
|
funcnName = abi::__cxa_demangle( beginFuncName, funcnName, &funcNameSize, &res );
|
|
unsigned int binaryOffset = strtoul( beginBinaryOffset, nullptr, 16 );
|
|
if ( res == 0 )
|
|
{
|
|
string funcnNameStr = ( funcnName ? funcnName : "" );
|
|
if ( funcnName && strncmp( funcnName, "Pol::", 5 ) == 0 )
|
|
funcnNameStr = ">> " + funcnNameStr;
|
|
|
|
if ( beginBinaryName && strlen( beginBinaryName ) )
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
|
|
funcnNameStr.c_str(), beginFuncOffset, beginBinaryName );
|
|
else
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s from %s\n", stackTraceStep, binaryOffset,
|
|
funcnNameStr.c_str(), beginFuncOffset );
|
|
stackTraceStep++;
|
|
}
|
|
else
|
|
{
|
|
if ( beginBinaryName && strlen( beginBinaryName ) )
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
|
|
beginFuncName, beginFuncOffset, beginBinaryName );
|
|
else
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s]\n", stackTraceStep, binaryOffset,
|
|
beginFuncName, beginFuncOffset );
|
|
stackTraceStep++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// print the raw trace, as it is better than nothing
|
|
sprintf( stringBuf, "#%02d %s\n", stackTraceStep, stackTraceList[i] );
|
|
stackTraceStep++;
|
|
}
|
|
|
|
// append the line to the result
|
|
result += string( stringBuf );
|
|
}
|
|
|
|
// memory cleanup
|
|
free( funcnName );
|
|
free( stackTraceList );
|
|
free( stringBuf );
|
|
|
|
return result;
|
|
}
|
|
|
|
static void handleSignalLinux( int signal, siginfo_t* signalInfo, void* arg )
|
|
{
|
|
(void)arg;
|
|
logExceptionSignal( signal );
|
|
if ( signalInfo != nullptr )
|
|
{
|
|
if ( signal == SIGSEGV )
|
|
{
|
|
if ( signalInfo->si_addr != nullptr )
|
|
printf( "Segmentation fault detected - faulty memory reference at location: %p\n",
|
|
signalInfo->si_addr );
|
|
else
|
|
printf( "Segmentation fault detected - null pointer reference\n" );
|
|
}
|
|
if ( signalInfo->si_errno != 0 )
|
|
printf( "This signal occurred because \"%s\"(%d)\n", strerror( signalInfo->si_errno ),
|
|
signalInfo->si_errno );
|
|
if ( signalInfo->si_code != 0 )
|
|
printf( "Signal code is %d\n", signalInfo->si_code );
|
|
}
|
|
ExceptionParser::handleExceptionSignal( signal );
|
|
}
|
|
|
|
static void handleStackTraceRequestLinux( int signal, siginfo_t* signalInfo, void* arg )
|
|
{
|
|
(void)signal;
|
|
(void)signalInfo;
|
|
(void)arg;
|
|
threadhelp::ThreadMap::Contents threadDesc;
|
|
threadhelp::threadmap.CopyContents( threadDesc );
|
|
|
|
fmt::Writer output;
|
|
output << "STACK TRACE for thread \"" << threadDesc[pthread_self()] << "\"(" << pthread_self()
|
|
<< "):\n";
|
|
output << ExceptionParser::getTrace() << "\n";
|
|
|
|
// print to stdout
|
|
printf( "%s", output.c_str() );
|
|
|
|
// print to error output
|
|
POLLOG_ERROR << output.str();
|
|
|
|
// wait here for logging facility to make sure everything was processed
|
|
if ( Clib::Logging::global_logger )
|
|
Clib::Logging::global_logger->wait_for_empty_queue();
|
|
}
|
|
|
|
void ExceptionParser::logAllStackTraces()
|
|
{
|
|
threadhelp::ThreadMap::Contents threadsDesc;
|
|
threadhelp::threadmap.CopyContents( threadsDesc );
|
|
for ( const auto& threadDesc : threadsDesc )
|
|
{
|
|
pthread_t threadID = (pthread_t)threadDesc.first;
|
|
|
|
if ( pthread_kill( threadID, SIGUSR1 ) != 0 )
|
|
{
|
|
fmt::Writer output;
|
|
output << "pthread_kill() failed to send SIGUSR1 to thread " << threadsDesc[threadID] << "("
|
|
<< threadID << ")\n";
|
|
fprintf( stderr, "%s", output.c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExceptionParser::initGlobalExceptionCatching()
|
|
{
|
|
struct sigaction sigAction;
|
|
|
|
memset( &sigAction, 0, sizeof( sigAction ) );
|
|
sigemptyset( &sigAction.sa_mask );
|
|
sigAction.sa_sigaction = handleSignalLinux;
|
|
sigAction.sa_flags = SA_SIGINFO;
|
|
sigaction( SIGINT, &sigAction, nullptr );
|
|
sigaction( SIGTERM, &sigAction, nullptr );
|
|
sigaction( SIGSEGV, &sigAction, nullptr );
|
|
sigaction( SIGABRT, &sigAction, nullptr );
|
|
sigAction.sa_sigaction = handleStackTraceRequestLinux;
|
|
sigaction( SIGUSR1, &sigAction, nullptr );
|
|
|
|
// set handler stack
|
|
stack_t tStack;
|
|
// mmap: no false positives for leak, plus guardpages to get SIGSEGV on memory overwrites
|
|
char* mem = static_cast<char*>( mmap( nullptr, SIGSTKSZ + 2 * getpagesize(),
|
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 ) );
|
|
mprotect( mem, getpagesize(), PROT_NONE );
|
|
mprotect( mem + getpagesize() + SIGSTKSZ, getpagesize(), PROT_NONE );
|
|
tStack.ss_sp = mem + getpagesize();
|
|
tStack.ss_size = SIGSTKSZ;
|
|
tStack.ss_flags = 0;
|
|
if ( sigaltstack( &tStack, nullptr ) == -1 )
|
|
{
|
|
printf( "Could not set signal handler stack\n" );
|
|
std::exit( 1 );
|
|
}
|
|
}
|
|
#else // _WIN32
|
|
string ExceptionParser::getTrace()
|
|
{
|
|
string result;
|
|
|
|
return result;
|
|
}
|
|
|
|
void ExceptionParser::logAllStackTraces() {}
|
|
|
|
void ExceptionParser::initGlobalExceptionCatching() {}
|
|
#endif // _WIN32
|
|
|
|
void ExceptionParser::configureProgramAbortReportingSystem( bool active, std::string server,
|
|
std::string url, std::string reporter )
|
|
{
|
|
m_programAbortReporting = active;
|
|
m_programAbortReportingServer = std::move( server );
|
|
m_programAbortReportingUrl = std::move( url );
|
|
m_programAbortReportingReporter = std::move( reporter );
|
|
}
|
|
|
|
bool ExceptionParser::programAbortReporting()
|
|
{
|
|
return m_programAbortReporting;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
} // namespace Clib
|
|
} // namespace Pol
|