Commit 47e384c5 authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Facebook GitHub Bot

folly: SafeAssert: variadic macros to enable more detailed error reporting from signal handlers

Summary:
`folly::Symbolizer` uses `FOLLY_SAFE_CHECK` -- which is signal-safe, but it only says "this thing broke".

I plan to changes these to add more details about what exactly broke:
from:
   FOLLY_SAFE_CHECK(die.abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry");
to
   FOLLY_SAFE_CHECK(die.abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry, found: ", die.abbr.tag);

Reviewed By: yfeldblum

Differential Revision: D25992552

fbshipit-source-id: ae678b45606afc519704767844a973d499c60c73
parent 9b6c06fa
......@@ -23,7 +23,6 @@
#include <folly/portability/Unistd.h>
namespace folly {
namespace detail {
namespace {
......@@ -442,35 +441,40 @@ constexpr std::pair<int, const char*> errors[] = {
};
#undef FOLLY_DETAIL_ERROR
} // namespace
namespace signal_safe {
void writeStderr(const char* s, size_t len) {
fileutil_detail::wrapFull(write, STDERR_FILENO, const_cast<char*>(s), len);
}
void writeStderr(const char* s) {
writeStderr(s, strlen(s));
}
void flushStderr() {
fileutil_detail::wrapNoInt(fsync, STDERR_FILENO);
}
} // namespace
void assertionFailure(
const char* expr,
const char* msg,
const char* file,
unsigned int line,
const char* function,
int error) {
void writeStderr(unsigned long x) {
char buf[to_ascii_size_max_decimal<uint64_t>()];
writeStderr(buf, to_ascii_decimal(buf, x));
}
void writeErrBegin(const char* expr, const char* msg) {
writeStderr("\n\nAssertion failure: ");
writeStderr(expr + 1, strlen(expr) - 2);
writeStderr("\nMessage: ");
writeStderr(msg);
}
[[noreturn]] void writeErrEnd(
const char* file, unsigned int line, const char* function, int error) {
writeStderr("\nFile: ");
writeStderr(file);
writeStderr("\nLine: ");
writeStderr(buf, to_ascii_decimal(buf, line));
writeStderr(line);
writeStderr("\nFunction: ");
writeStderr(function);
if (error) {
......@@ -478,7 +482,7 @@ void assertionFailure(
// the symbolic constant is necessary since actual numbers may vary
// for simplicity, do not attempt to mimic strerror printing descriptions
writeStderr("\nError: ");
writeStderr(buf, to_ascii_decimal(buf, error));
writeStderr(error);
writeStderr(" (");
// the list is not required to be sorted; but the program is about to die
auto const pred = [=](auto const e) { return e.first == error; };
......@@ -491,5 +495,5 @@ void assertionFailure(
abort();
}
} // namespace detail
} // namespace signal_safe
} // namespace folly
......@@ -21,47 +21,53 @@
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#define FOLLY_SAFE_CHECK_IMPL(expr, expr_s, msg, error) \
((expr) ? static_cast<void>(0) \
: ::folly::detail::assertionFailure( \
FOLLY_PP_STRINGIZE(expr_s), \
(msg), \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
error))
#define FOLLY_SAFE_CHECK_IMPL(expr, expr_s, msg, error, ...) \
((expr) ? static_cast<void>(0) \
: (::folly::signal_safe::writeErrBegin( \
FOLLY_PP_STRINGIZE(expr_s), (msg)), \
::folly::signal_safe::writeStderrPack(__VA_ARGS__), \
::folly::signal_safe::writeErrEnd( \
__FILE__, __LINE__, __PRETTY_FUNCTION__, error)))
/**
* Verify that the expression is true. If not, prints an error message
* (containing msg) to stderr and abort()s. Just like CHECK(), but only
* logs to stderr and only does async-signal-safe calls.
*/
#define FOLLY_SAFE_CHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), 0)
#define FOLLY_SAFE_CHECK(expr, msg, ...) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), 0, __VA_ARGS__);
/**
* In debug mode, verify that the expression is true. Otherwise, do nothing
* (do not even evaluate expr). Just like DCHECK(), but only logs to stderr and
* only does async-signal-safe calls.
*/
#define FOLLY_SAFE_DCHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL(!::folly::kIsDebug || (expr), (expr), (msg), 0)
#define FOLLY_SAFE_DCHECK(expr, msg, ...) \
FOLLY_SAFE_CHECK_IMPL( \
!::folly::kIsDebug || (expr), (expr), (msg), 0, __VA_ARGS__)
/**
* Like FOLLY_SAFE_CHECK, but also prints errno.
*/
#define FOLLY_SAFE_PCHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), errno)
#define FOLLY_SAFE_PCHECK(expr, msg, ...) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), errno, __VA_ARGS__)
namespace folly {
namespace detail {
namespace signal_safe {
[[noreturn]] void assertionFailure(
const char* expr,
const char* msg,
const char* file,
unsigned int line,
const char* function,
int error);
} // namespace detail
void writeStderr(const char*);
void writeStderr(unsigned long int);
template <typename... A>
void writeStderrPack(A... a) {
// NOTE: C++14-compatible version of comma fold expression.
using _ = int[];
void(_{0, (writeStderr(a), 0)...});
}
void writeErrBegin(const char* expr, const char* msg);
[[noreturn]] void writeErrEnd(
const char* file, unsigned int line, const char* function, int error);
} // namespace signal_safe
} // namespace folly
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