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

polserver / polserver / 29352231943

14 Jul 2026 05:04PM UTC coverage: 61.419% (+0.07%) from 61.349%
29352231943

push

github

web-flow
Misc modernizations and improvments (#896)

* fixed_allocator cleanup
template argument is now the type and not the size
general cleanup, rewrote refill loop to better understand whats
happening
possibility to use different alignments (not needed for the used types)

* adapted fixed_allocator usage

* simplified message_queue conditial wait, removed unused header

* use moveonlyfunction for logging queue

* cleanup and performance improvment for clienttransmit

* use moveonlyfunction for sql

* fixed use after move

* TaskThreadPool uses moveonlyfunction

* catch exception locally without stopping the complete workerthread

* message_queue pop with timeout

* DynTaskThreadPool changes

- using move_only_function
- general simplification
- minimum of 4 threads
- added idle timeout to get rid of workers

* simplified auxpoolthread usage

* fixed threadmap initialization

* to avoid static initialization problem dont prefill worker threada in
the constructor
update macos to latest which hopefully supports jthreads

* removed debug logs

* seems macos-latest is not always 26, explicitly use it

* added jitter for timeout
secured the logic when to spawn a new thread more
busyguard is now used to track a message compare value against
live_threads to decide if a new thread should be spawned
unique name per poolworker

199 of 248 new or added lines in 15 files covered. (80.24%)

1 existing line in 1 file now uncovered.

45056 of 73359 relevant lines covered (61.42%)

634055.61 hits per line

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

11.58
/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
{
53
void getSignalDescription( int signal, string& signalName, string& signalDescription )
×
54
{
55
  switch ( signal )
×
56
  {
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:
123
    signalName = "SIGUSR1";
×
124
    signalDescription = "user-defined signal 1";
×
125
    break;
×
126
  case 17:
×
127
  case 31:
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
  }
136
}
×
137

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

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

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
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

208
  return result;
×
209
}
210

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
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",
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;
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
  {
247
    fprintf( stderr, "getaddrinfo() failed for \"%s\" due to \"%s\"(code: %d)\n", host.c_str(),
×
248
             gai_strerror( res ), res );
249
    std::_Exit( 1 );
×
250
  }
251

252
  switch ( serverAddr->ai_addr->sa_family )
×
253
  {
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

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

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
272
  socketFD = socket( serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol );
×
273

274
  /**
275
   * connect to the bug tracking server
276
   */
277
  if ( ( res = connect( socketFD, serverAddr->ai_addr, (int)serverAddr->ai_addrlen ) ) != 0 )
×
278
  {
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

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

286
/**
287
 * send the request
288
 */
289
#if !defined( _WIN32 ) && !defined( __APPLE__ )
290
  send( socketFD, request, strlen( request ), MSG_NOSIGNAL );
×
291
#else
292
  send( socketFD, request, (int)strlen( request ), 0 );
293
#endif
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__ )
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
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
316
  close( socketFD );
×
317
#else
318
  closesocket( socketFD );
319
#endif
320
}
×
321
}  // namespace
322

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
   */
328
  string host = "polserver.com";
×
329
  string url = "/pol/report_program_abort.php";
×
330
  if ( !m_programAbortReportingServer.empty() )
×
331
  {
332
    host = m_programAbortReportingServer;
×
333
    if ( !m_programAbortReportingUrl.empty() )
×
334
      url = m_programAbortReportingUrl;
×
335
  }
336

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

368
  // execute the POST request
369
  doHttpPOST( host, url, content );
×
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
     */
385
    printf(
×
386
        "########################################################################################"
387
        "\n" );
388
    if ( m_programAbortReporting )
×
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" );
394
    string tStackTrace = ExceptionParser::getTrace();
×
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" );
×
411
    printf(
×
412
        "########################################################################################"
413
        "\n" );
414
    fflush( stdout );
×
415

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

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

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

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

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

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

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

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

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

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

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

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

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

493
void ExceptionParser::logAllStackTraces()
×
494
{
495
  threadhelp::ThreadMap::Contents threadsDesc;
×
NEW
496
  threadhelp::threadmap_instance().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",
×
504
               fmt::format( "pthread_kill() failed to send SIGUSR1 to thread {}({})\n",
×
505
                            threadsDesc[threadID], threadID )
×
506
                   .c_str() );
507
    }
508
  }
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
  {
538
    printf( "Could not set signal handler stack\n" );
×
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

559
string ExceptionParser::getTrace()
1✔
560
{
561
  auto stack = boost::stacktrace::stacktrace::from_current_exception();
1✔
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
565
  if ( stack.empty() )
1✔
566
    stack = boost::stacktrace::stacktrace();
×
567
  return boost::stacktrace::to_string( stack );
2✔
568
}
1✔
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

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 TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc