From: Alex Rousskov Date: Sun, 4 Jun 2017 15:32:01 +0000 (-0600) Subject: Do not die silently when dying via std::terminate(). X-Git-Tag: M-staged-PR71~145 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ebdb0ef1bd1f2b105bce3db116e6345eceed7e06;p=thirdparty%2Fsquid.git Do not die silently when dying via std::terminate(). Report exception failures that call std::terminate(). Exceptions unwind stack towards main() and sooner or later get handled/reported by Squid. However, exception _failures_ just call std::terminate(), which aborts Squid without the stack unwinding. By default, a std::terminate() call usually results in a silent Squid process death because some default std::terminate_handler implementations do not say anything at all while others write to stderr which Squid redirects to /dev/null by default. Many different problems trigger std::terminate() calls. Most of them are rare, but, after the C++11 migration, one category became likely in Squid: A throwing destructor. Destructors in C++11 are implicitly "noexcept" by default, and many old Squid destructors might throw. These reporting changes do not bypass or eliminate any failures. --- diff --git a/src/main.cc b/src/main.cc index f6e0adedc9..6c4e5d70d7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1338,6 +1338,39 @@ mainInitialize(void) configured_once = 1; } +/// describes active (i.e., thrown but not yet handled) exception +static std::ostream & +CurrentException(std::ostream &os) +{ + if (std::current_exception()) { + try { + throw; // re-throw to recognize the exception type + } + catch (const std::exception &ex) { + os << ex.what(); + } + catch (...) { + os << "[unknown exception type]"; + } + } else { + os << "[no active exception]"; + } + return os; +} + +static void +OnTerminate() +{ + // ignore recursive calls to avoid termination loops + static bool terminating = false; + if (terminating) + return; + terminating = true; + + debugs(1, DBG_CRITICAL, "FATAL: Dying from an exception handling failure; exception: " << CurrentException); + abort(); +} + /// unsafe main routine -- may throw int SquidMain(int argc, char **argv); /// unsafe main routine wrapper to catch exceptions @@ -1371,12 +1404,15 @@ main(int argc, char **argv) static int SquidMainSafe(int argc, char **argv) { + (void)std::set_terminate(&OnTerminate); + // XXX: This top-level catch works great for startup, but, during runtime, + // it erases valuable stack info. TODO: Let stack-preserving OnTerminate() + // handle FATAL runtime errors by splitting main code into protected + // startup, unprotected runtime, and protected termination sections! try { return SquidMain(argc, argv); - } catch (const std::exception &e) { - debugs(1, DBG_CRITICAL, "FATAL: " << e.what()); } catch (...) { - debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception."); + debugs(1, DBG_CRITICAL, "FATAL: " << CurrentException); } return -1; // TODO: return EXIT_FAILURE instead }