Skip to content

Commit

Permalink
feat: support failure functions that throw
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiud committed Feb 5, 2024
1 parent 68b6ce3 commit 9b6ba41
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 24 deletions.
10 changes: 6 additions & 4 deletions src/glog/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,10 @@ using PrefixFormatterCallback = void (*)(std::ostream&, const LogMessage&,
GLOG_EXPORT void InstallPrefixFormatter(PrefixFormatterCallback callback,
void* data = nullptr);

// Install a function which will be called after LOG(FATAL).
GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func);
// Install a function which will be called after LOG(FATAL). Returns the
// previously set function.
GLOG_EXPORT logging_fail_func_t
InstallFailureFunction(logging_fail_func_t fail_func);

[[deprecated(
"Use the type-safe std::chrono::minutes EnableLogCleaner overload "
Expand Down Expand Up @@ -1332,7 +1334,7 @@ class GLOG_EXPORT LogMessage {
LogMessage(const char* file, int line,
const logging::internal::CheckOpString& result);

~LogMessage();
~LogMessage() noexcept(false);

// Flush a buffered message to the sink set in the constructor. Always
// called by the destructor, it may also be called from elsewhere if
Expand Down Expand Up @@ -1409,7 +1411,7 @@ class GLOG_EXPORT LogMessageFatal : public LogMessage {
LogMessageFatal(const char* file, int line);
LogMessageFatal(const char* file, int line,
const logging::internal::CheckOpString& result);
[[noreturn]] ~LogMessageFatal();
[[noreturn]] ~LogMessageFatal() noexcept(false);
};

// A non-macro interface to the log facility; (useful
Expand Down
13 changes: 12 additions & 1 deletion src/googletest.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,19 @@ void InitGoogleTest(int*, char**) {}
} \
} while (0)

vector<void (*)()> g_testlist; // the tests to run
# define EXPECT_THROW(statement, exception) \
do { \
try { \
statement; \
} catch (const exception&) { \
printf("ok\n"); \
} catch (...) { \
fprintf(stderr, "%s\n", "Unexpected exception thrown"); \
exit(EXIT_FAILURE); \
} \
} while (0)

vector<void (*)()> g_testlist; // the tests to run
# define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
Expand Down
42 changes: 23 additions & 19 deletions src/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1723,8 +1723,9 @@ const char* LogMessage::fullname() const noexcept { return data_->fullname_; }
const char* LogMessage::basename() const noexcept { return data_->basename_; }
const LogMessageTime& LogMessage::time() const noexcept { return time_; }

LogMessage::~LogMessage() {
LogMessage::~LogMessage() noexcept(false) {
Flush();
bool fail = data_->severity_ == GLOG_FATAL && exit_on_dfatal;
#ifdef GLOG_THREAD_LOCAL_STORAGE
if (data_ == static_cast<void*>(&thread_msg_data)) {
data_->~LogMessageData();
Expand All @@ -1735,6 +1736,24 @@ LogMessage::~LogMessage() {
#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
delete allocated_;
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
#if defined(__cpp_lib_uncaught_exceptions) && \
(__cpp_lib_uncaught_exceptions >= 201411L)
if (std::uncaught_exceptions() == 0)
#else
if (!std::uncaught_exception())
#endif
{
if (fail) {
const char* message = "*** Check failure stack trace: ***\n";
if (write(fileno(stderr), message, strlen(message)) < 0) {
// Ignore errors.
}
AlsoErrorWrite(GLOG_FATAL,
glog_internal_namespace_::ProgramInvocationShortName(),
message);
Fail();
}
}
}

int LogMessage::preserved_errno() const { return data_->preserved_errno_; }
Expand Down Expand Up @@ -1894,22 +1913,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
}
}

// release the lock that our caller (directly or indirectly)
// LogMessage::~LogMessage() grabbed so that signal handlers
// can use the logging facility. Alternately, we could add
// an entire unsafe logging interface to bypass locking
// for signal handlers but this seems simpler.
log_mutex.unlock();
LogDestination::WaitForSinks(data_);

const char* message = "*** Check failure stack trace: ***\n";
if (write(fileno(stderr), message, strlen(message)) < 0) {
// Ignore errors.
}
AlsoErrorWrite(GLOG_FATAL,
glog_internal_namespace_::ProgramInvocationShortName(),
message);
Fail();
}
}

Expand Down Expand Up @@ -1941,8 +1945,8 @@ NullStreamFatal::~NullStreamFatal() {
std::abort();
}

void InstallFailureFunction(logging_fail_func_t fail_func) {
g_logging_fail_func = fail_func;
logging_fail_func_t InstallFailureFunction(logging_fail_func_t fail_func) {
return std::exchange(g_logging_fail_func, fail_func);
}

void LogMessage::Fail() { g_logging_fail_func(); }
Expand Down Expand Up @@ -2635,7 +2639,7 @@ LogMessageFatal::LogMessageFatal(const char* file, int line,
const logging::internal::CheckOpString& result)
: LogMessage(file, line, result) {}

LogMessageFatal::~LogMessageFatal() {
LogMessageFatal::~LogMessageFatal() noexcept(false) {
Flush();
LogMessage::Fail();
}
Expand Down
15 changes: 15 additions & 0 deletions src/logging_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <mutex>
#include <queue>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>
Expand Down Expand Up @@ -1571,3 +1572,17 @@ TEST(EmailLogging, MaliciousAddress) {
EXPECT_FALSE(
SendEmail("!/bin/[email protected]", "Example subject", "Example body"));
}

TEST(Logging, FatalThrow) {
auto const fail_func =
InstallFailureFunction(+[]()
#if defined(__has_attribute)
# if __has_attribute(noreturn)
__attribute__((noreturn))
# endif // __has_attribute(noreturn)
#endif // defined(__has_attribute)
{ throw std::logic_error{"fail"}; });
auto restore_fail = [fail_func] { InstallFailureFunction(fail_func); };
ScopedExit<decltype(restore_fail)> restore{restore_fail};
EXPECT_THROW({ LOG(FATAL) << "must throw to fail"; }, std::logic_error);
}

0 comments on commit 9b6ba41

Please sign in to comment.