• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 25918451630

15 May 2026 12:43PM UTC coverage: 60.929% (+2.1%) from 58.859%
25918451630

push

github

turleypol
added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

43 of 61 new or added lines in 2 files covered. (70.49%)

14455 existing lines in 345 files now uncovered.

44695 of 73356 relevant lines covered (60.93%)

449621.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

9.65
/pol-core/clib/Debugging/ExceptionParser.cpp
1
#include "ExceptionParser.h"
2

3
#include "../Program/ProgramConfig.h"
4
#include "../logfacility.h"
5
#include "../stlutil.h"
6
#include "../threadhelp.h"
7
#include "pol_global_config.h"
8

9
#include <cstddef>
10
#include <cstdlib>
11
#include <cstring>
12
#include <errno.h>
13
#include <signal.h>
14
#include <stdio.h>
15

16
#ifndef WINDOWS
17
#include <arpa/inet.h>
18
#include <cxxabi.h>
19
#include <execinfo.h>
20
#include <netdb.h>
21
#include <netinet/in.h>
22
#include <sys/mman.h>
23
#include <unistd.h>
24

25
#define SOCKET int
26
#else
27
#include "../Header_Windows.h"
28
#include "shlwapi.h"
29
#endif
30

31
#include <boost/stacktrace.hpp>
32

33
#define MAX_STACK_TRACE_DEPTH 200
34
#define MAX_STACK_TRACE_STEP_LENGTH 512
35

36

37
namespace Pol::Clib
38
{
39
using namespace std;
40

41
///////////////////////////////////////////////////////////////////////////////
42

43
bool ExceptionParser::m_programAbortReporting = false;
44
std::string ExceptionParser::m_programAbortReportingServer = "";
45
std::string ExceptionParser::m_programAbortReportingUrl = "";
46
std::string ExceptionParser::m_programAbortReportingReporter = "";
47
std::string ExceptionParser::m_programStart = Pol::Clib::Logging::LogSink::getTimeStamp();
48

49
///////////////////////////////////////////////////////////////////////////////
50

51
namespace
52
{
UNCOV
53
void getSignalDescription( int signal, string& signalName, string& signalDescription )
×
54
{
UNCOV
55
  switch ( signal )
×
56
  {
UNCOV
57
  case 1:
×
58
    signalName = "SIGHUP";
×
59
    signalDescription = "hangup detected on controlling terminal or death of controlling process";
×
60
    break;
×
61
  case 2:
×
62
    signalName = "SIGINT";
×
63
    signalDescription = "interrupt from keyboard";
×
64
    break;
×
65
  case 3:
×
66
    signalName = "SIGQUIT";
×
67
    signalDescription = "quit from keyboard";
×
68
    break;
×
69
  case 4:
×
70
    signalName = "SIGILL";
×
71
    signalDescription = "illegal Instruction";
×
72
    break;
×
73
  case 6:
×
74
    signalName = "SIGABRT";
×
75
    signalDescription = "abort signal from abort()";
×
76
    break;
×
77
  case 8:
×
78
    signalName = "SIGFPE";
×
79
    signalDescription = "floating point exception";
×
80
    break;
×
81
  case 9:
×
82
    signalName = "SIGKILL";
×
83
    signalDescription = "kill signal";
×
84
    break;
×
85
  case 10:
×
86
    signalName = "SIGBUS";
×
87
    signalDescription = "bus error";
×
88
    break;
×
89
  case 11:
×
90
    signalName = "SIGSEGV";
×
91
    signalDescription = "invalid memory reference";
×
92
    break;
×
93
  case 12:
×
94
    signalName = "SIGSYS";
×
95
    signalDescription = "bad argument to system call";
×
96
    break;
×
97
  case 13:
×
98
    signalName = "SIGPIPE";
×
99
    signalDescription = "broken pipe: write to pipe with no readers";
×
100
    break;
×
101
  case 14:
×
102
    signalName = "SIGALRM";
×
103
    signalDescription = "timer signal from alarm()";
×
104
    break;
×
105
  case 15:
×
106
    signalName = "SIGTERM";
×
107
    signalDescription = "termination signal";
×
108
    break;
×
109
  case 18:
×
110
    signalName = "SIGCONT";
×
111
    signalDescription = "continue signal from tty";
×
112
    break;
×
113
  case 19:
×
114
    signalName = "SIGSTOP";
×
115
    signalDescription = "stop signal from tty";
×
116
    break;
×
117
  case 20:
×
118
    signalName = "SIGTSTP";
×
119
    signalDescription = "stop signal from user (keyboard)";
×
120
    break;
×
121
  case 16:
×
122
  case 30:
UNCOV
123
    signalName = "SIGUSR1";
×
124
    signalDescription = "user-defined signal 1";
×
125
    break;
×
126
  case 17:
×
127
  case 31:
UNCOV
128
    signalName = "SIGUSR2";
×
129
    signalDescription = "user-defined signal 2";
×
130
    break;
×
131
  default:
×
132
    signalName = "unsupported signal";
×
133
    signalDescription = "unsupported signal occurred";
×
134
    break;
×
135
  }
UNCOV
136
}
×
137

138
#if !defined( _WIN32 ) && !defined( __APPLE__ )
UNCOV
139
void logExceptionSignal( int signal )
×
140
{
UNCOV
141
  string signalName;
×
142
  string signalDescription;
×
143

UNCOV
144
  getSignalDescription( signal, signalName, signalDescription );
×
145
  printf( "Signal \"%s\"(%d: %s) detected.\n", signalName.c_str(), signal,
×
146
          signalDescription.c_str() );
UNCOV
147
}
×
148
#endif
149

UNCOV
150
string getCompilerVersion()
×
151
{
152
#ifdef LINUX
153
  char result[256];
154
#ifdef __clang__
155
  snprintf( result, arsize( result ), "clang %d.%d.%d", __clang_major__, __clang_minor__,
156
            __clang_patchlevel__ );
157
#else
UNCOV
158
  snprintf( result, arsize( result ), "gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__,
×
159
            __GNUC_PATCHLEVEL__ );
160
#endif
161
#endif
162
#ifdef WINDOWS
163
  string result;
164
  switch ( _MSC_VER )
165
  {
166
  case 1900:
167
    result = "MSVC++ 14.0 (Visual Studio 2015)";
168
    break;
169
  case 1800:
170
    result = "MSVC++ 12.0 (Visual Studio 2013)";
171
    break;
172
  case 1700:
173
    result = "MSVC++ 11.0 (Visual Studio 2012)";
174
    break;
175
  case 1600:
176
    result = "MSVC++ 10.0 (Visual Studio 2010)";
177
    break;
178
  case 1500:
179
    result = "MSVC++ 9.0 (Visual Studio 2008)";
180
    break;
181
  case 1400:
182
    result = "MSVC++ 8.0 (Visual Studio 2005)";
183
    break;
184
  case 1310:
185
    result = "MSVC++ 7.1 (Visual Studio 2003)";
186
    break;
187
  case 1300:
188
    result = "MSVC++ 7.0";
189
    break;
190
  case 1200:
191
    result = "MSVC++ 6.0";
192
    break;
193
  case 1100:
194
    result = "MSVC++ 5.0";
195
    break;
196
  default:
197
#if ( _MSC_VER > 1800 )
198
    result = "MSVC++ newer than version 12.0";
199
#elif ( _MSC_VER < 1100 )
200
    result = "MSVC++ older than version 5.0";
201
#else
202
    result = "MSVC++ (some unsupported version)";
203
#endif
204
    break;
205
  }
206
#endif
207

UNCOV
208
  return result;
×
209
}
210

UNCOV
211
void doHttpPOST( const string& host, const string& url, const string& content )
×
212
{
213
#define MAXLINE 4096
214
  char request[MAXLINE + 1];
215
  SOCKET socketFD;
216
  char targetIP[INET6_ADDRSTRLEN];
217

218
/**
219
 * prepare the request
220
 */
221
#ifdef _MSC_VER
222
  _snprintf(
223
#else
UNCOV
224
  snprintf(
×
225
#endif
226
      request, MAXLINE,
227
      "POST %s HTTP/1.0\r\n"
228
      "Host: %s\r\n"
229
      "Content-Type: application/x-www-form-urlencoded\r\n"
230
      "User-Agent: POL in-app abort reporting system, %s\r\n"
231
      "Content-length: %d\r\n\r\n"
232
      "%s",
UNCOV
233
      url.c_str(), host.c_str(), POL_VERSION_ID, (int)content.size(), content.c_str() );
×
234

235
  /**
236
   * DNS lookup if needed
237
   */
238
  struct addrinfo* serverAddr;
239
  struct addrinfo hints;
UNCOV
240
  memset( &hints, 0, sizeof hints );
×
241
  hints.ai_family = AF_UNSPEC;  // IPv4 or IPv6
×
242
  hints.ai_flags = AI_ADDRCONFIG;
×
243
  hints.ai_socktype = SOCK_STREAM;
×
244
  int res = getaddrinfo( host.c_str(), "http", &hints, &serverAddr );
×
245
  if ( res != 0 )
×
246
  {
UNCOV
247
    fprintf( stderr, "getaddrinfo() failed for \"%s\" due to \"%s\"(code: %d)\n", host.c_str(),
×
248
             gai_strerror( res ), res );
UNCOV
249
    std::_Exit( 1 );
×
250
  }
251

UNCOV
252
  switch ( serverAddr->ai_addr->sa_family )
×
253
  {
UNCOV
254
  case AF_INET:
×
255
    if ( inet_ntop( AF_INET, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
×
256
                    INET_ADDRSTRLEN ) == nullptr )
×
257
      std::_Exit( 1 );
×
258
    break;
×
259

UNCOV
260
  case AF_INET6:
×
261
    if ( inet_ntop( AF_INET6, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
×
262
                    INET6_ADDRSTRLEN ) == nullptr )
×
263
      std::_Exit( 1 );
×
264
    break;
×
265

UNCOV
266
  default:
×
267
    fprintf( stderr, "Unknown address family found for %s\n", host.c_str() );
×
268
    std::_Exit( 1 );
×
269
  }
270

271
  // create the socket
UNCOV
272
  socketFD = socket( serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol );
×
273

274
  /**
275
   * connect to the bug tracking server
276
   */
UNCOV
277
  if ( ( res = connect( socketFD, serverAddr->ai_addr, (int)serverAddr->ai_addrlen ) ) != 0 )
×
278
  {
UNCOV
279
    fprintf( stderr, "connect() failed for server \"%s\"(IP: %s) due \"%s\"(%d)\n", host.c_str(),
×
280
             targetIP, strerror( errno ), errno );
×
281
    std::_Exit( 1 );
×
282
  }
283

UNCOV
284
  freeaddrinfo( serverAddr );  // not needed anymore
×
285

286
/**
287
 * send the request
288
 */
289
#if !defined( _WIN32 ) && !defined( __APPLE__ )
UNCOV
290
  send( socketFD, request, strlen( request ), MSG_NOSIGNAL );
×
291
#else
292
  send( socketFD, request, (int)strlen( request ), 0 );
293
#endif
UNCOV
294
  printf( "Abort report was sent to %s%s (IP: %s)\n", host.c_str(), url.c_str(), targetIP );
×
295

296
  /**
297
   * wait for some answers and print them on the screen
298
   */
299
  ssize_t readBytes;
300
  char answer[MAXLINE + 1];
301

302
#if !defined( _WIN32 ) && !defined( __APPLE__ )
UNCOV
303
  while ( ( readBytes = recv( socketFD, answer, MAXLINE, MSG_NOSIGNAL ) ) > 0 )
×
304
  {
305
#else
306
  while ( ( readBytes = recv( socketFD, answer, MAXLINE, 0 ) ) > 0 )
307
  {
308
#endif
UNCOV
309
    answer[readBytes] = '\0';
×
310
    printf( "Answer from bug tracking server:\n%s\n", answer );
×
311
    // skip the received answer and proceed
312
  }
313

314
// close the socket to the bug tracking server
315
#ifndef _WIN32
UNCOV
316
  close( socketFD );
×
317
#else
318
  closesocket( socketFD );
319
#endif
UNCOV
320
}
×
321
}  // namespace
322

UNCOV
323
void ExceptionParser::reportProgramAbort( const string& stackTrace, const string& reason )
×
324
{
325
  /**
326
   * set some default values if the abort occurs too early and pol.cfg wasn't parsed yet
327
   */
UNCOV
328
  string host = "polserver.com";
×
329
  string url = "/pol/report_program_abort.php";
×
330
  if ( !m_programAbortReportingServer.empty() )
×
331
  {
332
    host = m_programAbortReportingServer;
×
UNCOV
333
    if ( !m_programAbortReportingUrl.empty() )
×
334
      url = m_programAbortReportingUrl;
×
335
  }
336

337
  // create the abort description for the subsequent POST request
UNCOV
338
  string content = "email=" + m_programAbortReportingReporter +
×
339
                   "&"
340
                   "bin=" +
×
UNCOV
341
                   PROG_CONFIG::programName() +
×
342
                   "&"
343
                   "start_time=" +
×
UNCOV
344
                   m_programStart +
×
345
                   "&"
346
                   "abort_time=" +
×
UNCOV
347
                   Pol::Clib::Logging::LogSink::getTimeStamp() +
×
348
                   "&"
349
                   "reason=" +
×
UNCOV
350
                   reason +
×
351
                   "&"
352
                   "trace=" +
×
UNCOV
353
                   stackTrace +
×
354
                   "&"
355
                   "comp=" +
×
UNCOV
356
                   getCompilerVersion() +
×
357
                   "&"
358
                   "comp_time=" +
×
UNCOV
359
                   ProgramConfig::build_datetime() +
×
360
                   "&"
361
                   "build_target=" +
×
UNCOV
362
                   ProgramConfig::build_target() +
×
363
                   "&"
364
                   "build_revision=" POL_VERSION_ID
365
                   "&"
UNCOV
366
                   "misc=";
×
367

368
  // execute the POST request
UNCOV
369
  doHttpPOST( host, url, content );
×
UNCOV
370
}
×
371

372
void ExceptionParser::handleExceptionSignal( int signal )
×
373
{
374
  switch ( signal )
×
375
  {
376
  case SIGILL:
×
377
  case SIGFPE:
378
  case SIGSEGV:
379
  case SIGTERM:
380
  case SIGABRT:
381
  {
382
    /**
383
     * inform the user about the program abort
384
     */
UNCOV
385
    printf(
×
386
        "########################################################################################"
387
        "\n" );
UNCOV
388
    if ( m_programAbortReporting )
×
UNCOV
389
      printf( "POL will exit now. The following will be sent to the POL developers:\n\n" );
×
390
    else
391
      printf(
×
392
          "POL will exit now. Please, post the following to the forum: "
393
          "http://forums.polserver.com/.\n" );
UNCOV
394
    string tStackTrace = ExceptionParser::getTrace();
×
UNCOV
395
    printf( "%s", tStackTrace.c_str() );
×
396
    printf( "Admin contact: %s\n", m_programAbortReportingReporter.c_str() );
×
397
    printf( "Executable: %s\n", PROG_CONFIG::programName().c_str() );
×
398
    printf( "Start time: %s\n", m_programStart.c_str() );
×
399
    printf( "Current time: %s\n", Pol::Clib::Logging::LogSink::getTimeStamp().c_str() );
×
400
    printf( "\n" );
×
401
    printf( "Stack trace:\n%s", tStackTrace.c_str() );
×
402
    printf( "\n" );
×
403
    printf( "Compiler: %s\n", getCompilerVersion().c_str() );
×
404
    printf( "Compile time: %s\n", ProgramConfig::build_datetime().c_str() );
×
405
    printf( "Build target: %s\n", ProgramConfig::build_target().c_str() );
×
406
    printf( "Build revision: %s\n", POL_VERSION_ID );
×
407
#if defined( __GLIBC__ )
408
    printf( "GNU C library (compile time): %d.%d\n", __GLIBC__, __GLIBC_MINOR__ );
×
409
#endif
410
    printf( "\n" );
×
UNCOV
411
    printf(
×
412
        "########################################################################################"
413
        "\n" );
UNCOV
414
    fflush( stdout );
×
415

416
    /**
417
     * use the program abort reporting system
418
     */
UNCOV
419
    if ( m_programAbortReporting )
×
420
    {
421
      string signalName;
×
UNCOV
422
      string signalDescription;
×
423

424
      getSignalDescription( signal, signalName, signalDescription );
×
UNCOV
425
      ExceptionParser::reportProgramAbort(
×
426
          tStackTrace, "CRASH caused by signal " + signalName + " (" + signalDescription + ")" );
×
427
    }
×
428

429
    // finally, go to hell
UNCOV
430
    std::_Exit( 1 );
×
UNCOV
431
  }
×
432
  break;
433
  default:
×
UNCOV
434
    break;
×
435
  }
436
}
×
437

438
///////////////////////////////////////////////////////////////////////////////
439

UNCOV
440
ExceptionParser::ExceptionParser() = default;
×
441

442
ExceptionParser::~ExceptionParser() {}
×
443

444
///////////////////////////////////////////////////////////////////////////////
445

446
#if !defined( _WIN32 ) && !defined( __APPLE__ )
UNCOV
447
static void handleSignalLinux( int signal, siginfo_t* signalInfo, void* arg )
×
448
{
449
  (void)arg;
UNCOV
450
  logExceptionSignal( signal );
×
UNCOV
451
  if ( signalInfo != nullptr )
×
452
  {
453
    if ( signal == SIGSEGV )
×
454
    {
455
      if ( signalInfo->si_addr != nullptr )
×
UNCOV
456
        printf( "Segmentation fault detected - faulty memory reference at location: %p\n",
×
457
                signalInfo->si_addr );
458
      else
UNCOV
459
        printf( "Segmentation fault detected - null pointer reference\n" );
×
460
    }
461
    if ( signalInfo->si_errno != 0 )
×
UNCOV
462
      printf( "This signal occurred because \"%s\"(%d)\n", strerror( signalInfo->si_errno ),
×
463
              signalInfo->si_errno );
464
    if ( signalInfo->si_code != 0 )
×
UNCOV
465
      printf( "Signal code is %d\n", signalInfo->si_code );
×
466
  }
467
  ExceptionParser::handleExceptionSignal( signal );
×
UNCOV
468
}
×
469

470
static void handleStackTraceRequestLinux( int signal, siginfo_t* signalInfo, void* arg )
×
471
{
472
  (void)signal;
473
  (void)signalInfo;
474
  (void)arg;
UNCOV
475
  threadhelp::ThreadMap::Contents threadDesc;
×
UNCOV
476
  threadhelp::threadmap.CopyContents( threadDesc );
×
477

478
  std::string output = fmt::format( "STACK TRACE for thread \"{}\"({}):\n",
UNCOV
479
                                    threadDesc[pthread_self()], pthread_self() );
×
UNCOV
480
  output += ExceptionParser::getTrace() + '\n';
×
481

482
  // print to stdout
UNCOV
483
  printf( "%s", output.c_str() );
×
484

485
  // print to error output
UNCOV
486
  POLLOG_ERROR( output );
×
487

488
  // wait here for logging facility to make sure everything was processed
UNCOV
489
  if ( Clib::Logging::global_logger )
×
UNCOV
490
    Clib::Logging::global_logger->wait_for_empty_queue();
×
491
}
×
492

493
void ExceptionParser::logAllStackTraces()
×
494
{
495
  threadhelp::ThreadMap::Contents threadsDesc;
×
UNCOV
496
  threadhelp::threadmap.CopyContents( threadsDesc );
×
497
  for ( const auto& threadDesc : threadsDesc )
×
498
  {
499
    pthread_t threadID = (pthread_t)threadDesc.first;
×
500

501
    if ( pthread_kill( threadID, SIGUSR1 ) != 0 )
×
502
    {
503
      fprintf( stderr, "%s",
×
UNCOV
504
               fmt::format( "pthread_kill() failed to send SIGUSR1 to thread {}({})\n",
×
505
                            threadsDesc[threadID], threadID )
×
506
                   .c_str() );
507
    }
508
  }
UNCOV
509
}
×
510

511
void ExceptionParser::initGlobalExceptionCatching()
4,959✔
512
{
513
  struct sigaction sigAction;
514

515
  memset( &sigAction, 0, sizeof( sigAction ) );
4,959✔
516
  sigemptyset( &sigAction.sa_mask );
4,959✔
517
  sigAction.sa_sigaction = handleSignalLinux;
4,959✔
518
  sigAction.sa_flags = SA_SIGINFO;
4,959✔
519
  sigaction( SIGINT, &sigAction, nullptr );
4,959✔
520
  sigaction( SIGTERM, &sigAction, nullptr );
4,959✔
521
  sigaction( SIGSEGV, &sigAction, nullptr );
4,959✔
522
  sigaction( SIGABRT, &sigAction, nullptr );
4,959✔
523
  sigAction.sa_sigaction = handleStackTraceRequestLinux;
4,959✔
524
  sigaction( SIGUSR1, &sigAction, nullptr );
4,959✔
525

526
  // set handler stack
527
  stack_t tStack;
528
  // mmap: no false positives for leak, plus guardpages to get SIGSEGV on memory overwrites
529
  char* mem = static_cast<char*>( mmap( nullptr, SIGSTKSZ + 2 * getpagesize(),
4,959✔
530
                                        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 ) );
531
  mprotect( mem, getpagesize(), PROT_NONE );
4,959✔
532
  mprotect( mem + getpagesize() + SIGSTKSZ, getpagesize(), PROT_NONE );
4,959✔
533
  tStack.ss_sp = mem + getpagesize();
4,959✔
534
  tStack.ss_size = SIGSTKSZ;
4,959✔
535
  tStack.ss_flags = 0;
4,959✔
536
  if ( sigaltstack( &tStack, nullptr ) == -1 )
4,959✔
537
  {
UNCOV
538
    printf( "Could not set signal handler stack\n" );
×
UNCOV
539
    std::exit( 1 );
×
540
  }
541
}
4,959✔
542
#else  // _WIN32 || Apple
543

544
void ExceptionParser::logAllStackTraces() {}
545

546
void ExceptionParser::initGlobalExceptionCatching()
547
{
548
#if defined( _WIN32 )
549
  // see compile_defs.cmake
550
  // in addition add the executable path as searchpath
551
  wchar_t path[MAX_PATH];
552
  GetModuleFileNameW( nullptr, path, MAX_PATH );
553
  PathRemoveFileSpecW( path );
554
  SetEnvironmentVariableW( L"_NT_ALT_SYMBOL_PATH", path );
555
#endif
556
}
557
#endif  // _WIN32 || Apple
558

UNCOV
559
string ExceptionParser::getTrace()
×
560
{
561
  auto stack = boost::stacktrace::stacktrace::from_current_exception();
×
562
  // current_exception does not always work, eg no active exception
563
  // and needs linking with libboost_stacktrace_backtrace, which as of now is not possible with
564
  // Apple. Current stacktrace as fallback, which should give enough infos
UNCOV
565
  if ( stack.empty() )
×
UNCOV
566
    stack = boost::stacktrace::stacktrace();
×
567
  return boost::stacktrace::to_string( stack );
×
568
}
×
569

570
void ExceptionParser::configureProgramAbortReportingSystem( bool active, std::string server,
39✔
571
                                                            std::string url, std::string reporter )
572
{
573
  m_programAbortReporting = active;
39✔
574
  m_programAbortReportingServer = std::move( server );
39✔
575
  m_programAbortReportingUrl = std::move( url );
39✔
576
  m_programAbortReportingReporter = std::move( reporter );
39✔
577
}
39✔
578

UNCOV
579
bool ExceptionParser::programAbortReporting()
×
580
{
581
  return m_programAbortReporting;
×
582
}
583

584
///////////////////////////////////////////////////////////////////////////////
585
}  // namespace Pol::Clib
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc