]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Do not die silently when dying via std::terminate().
authorAlex Rousskov <rousskov@measurement-factory.com>
Sun, 18 Jun 2017 19:08:57 +0000 (07:08 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 18 Jun 2017 19:08:57 +0000 (07:08 +1200)
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.

src/main.cc

index 27f83d8f5ba6c53a86738291b9fe05b881de1515..3e277a980fafa9c91cf0172ae50f2f33dcc0b9f7 100644 (file)
@@ -1339,6 +1339,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
@@ -1372,12 +1405,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
 }