Commit ae7e1fd0 authored by Phil Willoughby's avatar Phil Willoughby Committed by Facebook Github Bot

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
parent aebb140d
......@@ -483,6 +483,7 @@ libfolly_la_SOURCES = \
portability/Unistd.cpp \
Random.cpp \
SafeAssert.cpp \
ScopeGuard.cpp \
SharedMutex.cpp \
Shell.cpp \
MicroLock.cpp \
......
/*
* 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 <iostream>
/*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";
}
......@@ -22,6 +22,7 @@
#include <type_traits>
#include <utility>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#include <folly/detail/UncaughtExceptionCounter.h>
......@@ -75,6 +76,17 @@ class ScopeGuardImplBase {
dismissed_ = true;
}
template <typename T>
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 <typename FunctionType>
......@@ -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 <typename FunctionType, bool executeOnException>
class ScopeGuardForNewException {
......@@ -205,7 +222,11 @@ class ScopeGuardForNewException {
~ScopeGuardForNewException() noexcept(executeOnException) {
if (executeOnException == exceptionCounter_.isNewUncaughtException()) {
function_();
if (executeOnException) {
ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_);
} else {
function_();
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment