From ae7e1fd07dc2c01baf23c294598fcc839c1e7c23 Mon Sep 17 00:00:00 2001 From: Phil Willoughby Date: Fri, 18 Nov 2016 08:08:19 -0800 Subject: [PATCH] Explain crash when exception is thrown from Scope Guard Summary: Print a message to `std::cerr` when the current program is about to call `std::terminate` because a `folly::ScopeGuard` callback threw an exception. This goes to `std::terminate` in the (common) cases when the `ScopeGuard` destructor is `noexcept` This gives the user a small clue as to what just happened, since the default diagnostics for this on some platforms do not help at all. Reviewed By: nbronson Differential Revision: D4061096 fbshipit-source-id: c3b534d4a36b095e08e46f375251b6fd416ccd68 --- folly/Makefile.am | 1 + folly/ScopeGuard.cpp | 27 +++++++++++++++++++++++++++ folly/ScopeGuard.h | 27 ++++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 folly/ScopeGuard.cpp diff --git a/folly/Makefile.am b/folly/Makefile.am index b353b1bf..768fdf6f 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -483,6 +483,7 @@ libfolly_la_SOURCES = \ portability/Unistd.cpp \ Random.cpp \ SafeAssert.cpp \ + ScopeGuard.cpp \ SharedMutex.cpp \ Shell.cpp \ MicroLock.cpp \ diff --git a/folly/ScopeGuard.cpp b/folly/ScopeGuard.cpp new file mode 100644 index 00000000..1a06f4bb --- /dev/null +++ b/folly/ScopeGuard.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ScopeGuard.h" + +#include + +/*static*/ void folly::ScopeGuardImplBase::warnAboutToCrash() noexcept { + // Ensure the availability of std::cerr + std::ios_base::Init ioInit; + std::cerr + << "This program will now terminate because a folly::ScopeGuard callback " + "threw an \nexception.\n"; +} diff --git a/folly/ScopeGuard.h b/folly/ScopeGuard.h index 940a3485..f56b2760 100644 --- a/folly/ScopeGuard.h +++ b/folly/ScopeGuard.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -75,6 +76,17 @@ class ScopeGuardImplBase { dismissed_ = true; } + template + FOLLY_ALWAYS_INLINE static void runAndWarnAboutToCrashOnException( + T& function) { + try { + function(); + } catch (...) { + warnAboutToCrash(); + throw; + } + } + protected: ScopeGuardImplBase() noexcept : dismissed_(false) {} @@ -88,6 +100,9 @@ class ScopeGuardImplBase { } bool dismissed_; + + private: + static void warnAboutToCrash() noexcept; }; template @@ -151,7 +166,9 @@ class ScopeGuardImpl : public ScopeGuardImplBase { void* operator new(std::size_t) = delete; - void execute() noexcept { function_(); } + void execute() noexcept { + runAndWarnAboutToCrashOnException(function_); + } FunctionType function_; }; @@ -185,7 +202,7 @@ namespace detail { * If the parameter is false, then the function is executed if no new uncaught * exceptions are present at the end of the scope. * - * Used to implement SCOPE_FAIL and SCOPE_SUCCES below. + * Used to implement SCOPE_FAIL and SCOPE_SUCCESS below. */ template class ScopeGuardForNewException { @@ -205,7 +222,11 @@ class ScopeGuardForNewException { ~ScopeGuardForNewException() noexcept(executeOnException) { if (executeOnException == exceptionCounter_.isNewUncaughtException()) { - function_(); + if (executeOnException) { + ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_); + } else { + function_(); + } } } -- 2.34.1