2

My C++ program has an embedded web server (based on CivetWeb). If an exception occurs while handling an HTTP request, I'd like to not crash, but I'd also like to trigger a core dump for future debugging.

Here's my current attempt.

// See http://stackoverflow.com/a/131539/25507
void create_dump(void)
{
  if(!fork()) {
    abort() || (*((void*)0) = 42);
  }
}

void HandleHttpRequest(mg_conn *conn)
{
  try {
    // Lots of application-specific logic
  } catch (std::exception& e) {
    create_dump();
    WriteHttp500(conn);
  }
}

This is mostly working. However, if I then bring up gdb to do a postmortem debugging session with the core dump, the stack trace is at the create_dump() line of HandleHttpRequest.

If I have a core dump of a catch block, is there any way to view the stack trace that threw the exception?

Or is there some better way of accomplishing my goal (of automatically turning uncaught exceptions into an HTTP 500 error code while also capturing full debugging information for them)?

Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
  • Do you really need a core dump, or can you just run a custom unwinder to collect the backtrace? That should be plenty of information for debugging. – Kerrek SB Mar 14 '16 at 18:52
  • @KerrekSB - A core dump would be ideal, but a custom unwinder would certainly be better than nothing. Do you have any starting points for information on writing one that could access the exception's stack trace from a catch block? (I tried a brief Google search but am unclear on how to proceed.) – Josh Kelley Mar 14 '16 at 18:57
  • If you're able and willing to change the thrown exception type, then I would look into boost exceptions, see http://stackoverflow.com/questions/691719/c-display-stack-trace-on-exception – inetknght Mar 14 '16 at 18:57
  • Also remember that a stack trace _may_ be useless in optimized builds because of frame pointer omission – inetknght Mar 14 '16 at 18:58
  • Something like libunwind comes to mind... – Kerrek SB Mar 14 '16 at 20:00

2 Answers2

0

There is no portable way to achieve what you want.

Non-portable way is to interpose extern "C" void __cxa_throw(void *, void *, void *) function from libstdc++.so, and dump your core from it before calling the original function from libstdc++.so.

More info on how to perform such interposition is here.

Notes:

  1. This will only work if you link against libstdc++.so (which you generally should anyway), and not libstdc++.a.
  2. You don't have to use LD_PRELOAD, you can put interposer into the main executable.
  3. Using fork() to dump core is very heavy weight, and doesn't work well (well, doesn't work at all) for multi-threaded programs. You may be better off using Google ELF coredumper.
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
0

I have been working on a library that can be attached to C++ programs at run-time since late last year, and recently opensourced it here. It is for Linux.

Coincidentally, it does mostly what is explained by Employed Russian; it interposes throw and catch statements and print backtraces from there. No need to recompile or link against target applications. Just load it using LD_PRELOAD when you run your application.

It is also extensible. You can add backtrace printing to C/C++ functions with small amount of interposing code. You need to know what you are doing, though.

It does not demangle C++ function names or call addr2line because that adds extra overhead to the target applications and may affect execution timings. After all, you can use c++filt or addr2line manually after program exits.

I wrote this library in order to troubleshoot a tough coredump problem whereby SEGFAULT involved the catch-all block. It only occurred in customer's lab environment, and the problem disappeared when gdb is attached.

mizubasho
  • 91
  • 1
  • 7