Commit 09634ef5 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

FOLLY_SAFE_PCHECK

Summary: [Folly] `FOLLY_SAFE_PCHECK`, for reporting errors from C standard library functions which may set errno from within code which must be reentrant.

Reviewed By: nbronson

Differential Revision: D19222785

fbshipit-source-id: 532ccee39c9d180b9b17edbd31517c09024539d7
parent 1cd1bfb6
......@@ -16,6 +16,8 @@
#include <folly/lang/SafeAssert.h>
#include <algorithm>
#include <folly/Conv.h>
#include <folly/FileUtil.h>
......@@ -23,12 +25,429 @@ namespace folly {
namespace detail {
namespace {
// script (centos):
//
// for e in $(
// cat /usr/include/asm*/errno*.h | awk '{print $2}' | grep -P '^E' | sort
// ) ; do
// echo "#if defined($e)"
// echo " FOLLY_DETAIL_ERROR($e),"
// echo "#endif"
// done
#define FOLLY_DETAIL_ERROR(name) \
{ name, #name }
constexpr std::pair<int, const char*> errors[] = {
#if defined(E2BIG)
FOLLY_DETAIL_ERROR(E2BIG),
#endif
#if defined(EACCES)
FOLLY_DETAIL_ERROR(EACCES),
#endif
#if defined(EADDRINUSE)
FOLLY_DETAIL_ERROR(EADDRINUSE),
#endif
#if defined(EADDRNOTAVAIL)
FOLLY_DETAIL_ERROR(EADDRNOTAVAIL),
#endif
#if defined(EADV)
FOLLY_DETAIL_ERROR(EADV),
#endif
#if defined(EAFNOSUPPORT)
FOLLY_DETAIL_ERROR(EAFNOSUPPORT),
#endif
#if defined(EAGAIN)
FOLLY_DETAIL_ERROR(EAGAIN),
#endif
#if defined(EALREADY)
FOLLY_DETAIL_ERROR(EALREADY),
#endif
#if defined(EBADE)
FOLLY_DETAIL_ERROR(EBADE),
#endif
#if defined(EBADF)
FOLLY_DETAIL_ERROR(EBADF),
#endif
#if defined(EBADFD)
FOLLY_DETAIL_ERROR(EBADFD),
#endif
#if defined(EBADMSG)
FOLLY_DETAIL_ERROR(EBADMSG),
#endif
#if defined(EBADR)
FOLLY_DETAIL_ERROR(EBADR),
#endif
#if defined(EBADRQC)
FOLLY_DETAIL_ERROR(EBADRQC),
#endif
#if defined(EBADSLT)
FOLLY_DETAIL_ERROR(EBADSLT),
#endif
#if defined(EBFONT)
FOLLY_DETAIL_ERROR(EBFONT),
#endif
#if defined(EBUSY)
FOLLY_DETAIL_ERROR(EBUSY),
#endif
#if defined(ECANCELED)
FOLLY_DETAIL_ERROR(ECANCELED),
#endif
#if defined(ECHILD)
FOLLY_DETAIL_ERROR(ECHILD),
#endif
#if defined(ECHRNG)
FOLLY_DETAIL_ERROR(ECHRNG),
#endif
#if defined(ECOMM)
FOLLY_DETAIL_ERROR(ECOMM),
#endif
#if defined(ECONNABORTED)
FOLLY_DETAIL_ERROR(ECONNABORTED),
#endif
#if defined(ECONNREFUSED)
FOLLY_DETAIL_ERROR(ECONNREFUSED),
#endif
#if defined(ECONNRESET)
FOLLY_DETAIL_ERROR(ECONNRESET),
#endif
#if defined(EDEADLK)
FOLLY_DETAIL_ERROR(EDEADLK),
#endif
#if defined(EDEADLOCK)
FOLLY_DETAIL_ERROR(EDEADLOCK),
#endif
#if defined(EDESTADDRREQ)
FOLLY_DETAIL_ERROR(EDESTADDRREQ),
#endif
#if defined(EDOM)
FOLLY_DETAIL_ERROR(EDOM),
#endif
#if defined(EDOTDOT)
FOLLY_DETAIL_ERROR(EDOTDOT),
#endif
#if defined(EDQUOT)
FOLLY_DETAIL_ERROR(EDQUOT),
#endif
#if defined(EEXIST)
FOLLY_DETAIL_ERROR(EEXIST),
#endif
#if defined(EFAULT)
FOLLY_DETAIL_ERROR(EFAULT),
#endif
#if defined(EFBIG)
FOLLY_DETAIL_ERROR(EFBIG),
#endif
#if defined(EHOSTDOWN)
FOLLY_DETAIL_ERROR(EHOSTDOWN),
#endif
#if defined(EHOSTUNREACH)
FOLLY_DETAIL_ERROR(EHOSTUNREACH),
#endif
#if defined(EHWPOISON)
FOLLY_DETAIL_ERROR(EHWPOISON),
#endif
#if defined(EIDRM)
FOLLY_DETAIL_ERROR(EIDRM),
#endif
#if defined(EILSEQ)
FOLLY_DETAIL_ERROR(EILSEQ),
#endif
#if defined(EINPROGRESS)
FOLLY_DETAIL_ERROR(EINPROGRESS),
#endif
#if defined(EINTR)
FOLLY_DETAIL_ERROR(EINTR),
#endif
#if defined(EINVAL)
FOLLY_DETAIL_ERROR(EINVAL),
#endif
#if defined(EIO)
FOLLY_DETAIL_ERROR(EIO),
#endif
#if defined(EISCONN)
FOLLY_DETAIL_ERROR(EISCONN),
#endif
#if defined(EISDIR)
FOLLY_DETAIL_ERROR(EISDIR),
#endif
#if defined(EISNAM)
FOLLY_DETAIL_ERROR(EISNAM),
#endif
#if defined(EKEYEXPIRED)
FOLLY_DETAIL_ERROR(EKEYEXPIRED),
#endif
#if defined(EKEYREJECTED)
FOLLY_DETAIL_ERROR(EKEYREJECTED),
#endif
#if defined(EKEYREVOKED)
FOLLY_DETAIL_ERROR(EKEYREVOKED),
#endif
#if defined(EL2HLT)
FOLLY_DETAIL_ERROR(EL2HLT),
#endif
#if defined(EL2NSYNC)
FOLLY_DETAIL_ERROR(EL2NSYNC),
#endif
#if defined(EL3HLT)
FOLLY_DETAIL_ERROR(EL3HLT),
#endif
#if defined(EL3RST)
FOLLY_DETAIL_ERROR(EL3RST),
#endif
#if defined(ELIBACC)
FOLLY_DETAIL_ERROR(ELIBACC),
#endif
#if defined(ELIBBAD)
FOLLY_DETAIL_ERROR(ELIBBAD),
#endif
#if defined(ELIBEXEC)
FOLLY_DETAIL_ERROR(ELIBEXEC),
#endif
#if defined(ELIBMAX)
FOLLY_DETAIL_ERROR(ELIBMAX),
#endif
#if defined(ELIBSCN)
FOLLY_DETAIL_ERROR(ELIBSCN),
#endif
#if defined(ELNRNG)
FOLLY_DETAIL_ERROR(ELNRNG),
#endif
#if defined(ELOOP)
FOLLY_DETAIL_ERROR(ELOOP),
#endif
#if defined(EMEDIUMTYPE)
FOLLY_DETAIL_ERROR(EMEDIUMTYPE),
#endif
#if defined(EMFILE)
FOLLY_DETAIL_ERROR(EMFILE),
#endif
#if defined(EMLINK)
FOLLY_DETAIL_ERROR(EMLINK),
#endif
#if defined(EMSGSIZE)
FOLLY_DETAIL_ERROR(EMSGSIZE),
#endif
#if defined(EMULTIHOP)
FOLLY_DETAIL_ERROR(EMULTIHOP),
#endif
#if defined(ENAMETOOLONG)
FOLLY_DETAIL_ERROR(ENAMETOOLONG),
#endif
#if defined(ENAVAIL)
FOLLY_DETAIL_ERROR(ENAVAIL),
#endif
#if defined(ENETDOWN)
FOLLY_DETAIL_ERROR(ENETDOWN),
#endif
#if defined(ENETRESET)
FOLLY_DETAIL_ERROR(ENETRESET),
#endif
#if defined(ENETUNREACH)
FOLLY_DETAIL_ERROR(ENETUNREACH),
#endif
#if defined(ENFILE)
FOLLY_DETAIL_ERROR(ENFILE),
#endif
#if defined(ENOANO)
FOLLY_DETAIL_ERROR(ENOANO),
#endif
#if defined(ENOBUFS)
FOLLY_DETAIL_ERROR(ENOBUFS),
#endif
#if defined(ENOCSI)
FOLLY_DETAIL_ERROR(ENOCSI),
#endif
#if defined(ENODATA)
FOLLY_DETAIL_ERROR(ENODATA),
#endif
#if defined(ENODEV)
FOLLY_DETAIL_ERROR(ENODEV),
#endif
#if defined(ENOENT)
FOLLY_DETAIL_ERROR(ENOENT),
#endif
#if defined(ENOEXEC)
FOLLY_DETAIL_ERROR(ENOEXEC),
#endif
#if defined(ENOKEY)
FOLLY_DETAIL_ERROR(ENOKEY),
#endif
#if defined(ENOLCK)
FOLLY_DETAIL_ERROR(ENOLCK),
#endif
#if defined(ENOLINK)
FOLLY_DETAIL_ERROR(ENOLINK),
#endif
#if defined(ENOMEDIUM)
FOLLY_DETAIL_ERROR(ENOMEDIUM),
#endif
#if defined(ENOMEM)
FOLLY_DETAIL_ERROR(ENOMEM),
#endif
#if defined(ENOMSG)
FOLLY_DETAIL_ERROR(ENOMSG),
#endif
#if defined(ENONET)
FOLLY_DETAIL_ERROR(ENONET),
#endif
#if defined(ENOPKG)
FOLLY_DETAIL_ERROR(ENOPKG),
#endif
#if defined(ENOPROTOOPT)
FOLLY_DETAIL_ERROR(ENOPROTOOPT),
#endif
#if defined(ENOSPC)
FOLLY_DETAIL_ERROR(ENOSPC),
#endif
#if defined(ENOSR)
FOLLY_DETAIL_ERROR(ENOSR),
#endif
#if defined(ENOSTR)
FOLLY_DETAIL_ERROR(ENOSTR),
#endif
#if defined(ENOSYS)
FOLLY_DETAIL_ERROR(ENOSYS),
#endif
#if defined(ENOTBLK)
FOLLY_DETAIL_ERROR(ENOTBLK),
#endif
#if defined(ENOTCONN)
FOLLY_DETAIL_ERROR(ENOTCONN),
#endif
#if defined(ENOTDIR)
FOLLY_DETAIL_ERROR(ENOTDIR),
#endif
#if defined(ENOTEMPTY)
FOLLY_DETAIL_ERROR(ENOTEMPTY),
#endif
#if defined(ENOTNAM)
FOLLY_DETAIL_ERROR(ENOTNAM),
#endif
#if defined(ENOTRECOVERABLE)
FOLLY_DETAIL_ERROR(ENOTRECOVERABLE),
#endif
#if defined(ENOTSOCK)
FOLLY_DETAIL_ERROR(ENOTSOCK),
#endif
#if defined(ENOTTY)
FOLLY_DETAIL_ERROR(ENOTTY),
#endif
#if defined(ENOTUNIQ)
FOLLY_DETAIL_ERROR(ENOTUNIQ),
#endif
#if defined(ENXIO)
FOLLY_DETAIL_ERROR(ENXIO),
#endif
#if defined(EOPNOTSUPP)
FOLLY_DETAIL_ERROR(EOPNOTSUPP),
#endif
#if defined(EOVERFLOW)
FOLLY_DETAIL_ERROR(EOVERFLOW),
#endif
#if defined(EOWNERDEAD)
FOLLY_DETAIL_ERROR(EOWNERDEAD),
#endif
#if defined(EPERM)
FOLLY_DETAIL_ERROR(EPERM),
#endif
#if defined(EPFNOSUPPORT)
FOLLY_DETAIL_ERROR(EPFNOSUPPORT),
#endif
#if defined(EPIPE)
FOLLY_DETAIL_ERROR(EPIPE),
#endif
#if defined(EPROTO)
FOLLY_DETAIL_ERROR(EPROTO),
#endif
#if defined(EPROTONOSUPPORT)
FOLLY_DETAIL_ERROR(EPROTONOSUPPORT),
#endif
#if defined(EPROTOTYPE)
FOLLY_DETAIL_ERROR(EPROTOTYPE),
#endif
#if defined(ERANGE)
FOLLY_DETAIL_ERROR(ERANGE),
#endif
#if defined(EREMCHG)
FOLLY_DETAIL_ERROR(EREMCHG),
#endif
#if defined(EREMOTE)
FOLLY_DETAIL_ERROR(EREMOTE),
#endif
#if defined(EREMOTEIO)
FOLLY_DETAIL_ERROR(EREMOTEIO),
#endif
#if defined(ERESTART)
FOLLY_DETAIL_ERROR(ERESTART),
#endif
#if defined(ERFKILL)
FOLLY_DETAIL_ERROR(ERFKILL),
#endif
#if defined(EROFS)
FOLLY_DETAIL_ERROR(EROFS),
#endif
#if defined(ESHUTDOWN)
FOLLY_DETAIL_ERROR(ESHUTDOWN),
#endif
#if defined(ESOCKTNOSUPPORT)
FOLLY_DETAIL_ERROR(ESOCKTNOSUPPORT),
#endif
#if defined(ESPIPE)
FOLLY_DETAIL_ERROR(ESPIPE),
#endif
#if defined(ESRCH)
FOLLY_DETAIL_ERROR(ESRCH),
#endif
#if defined(ESRMNT)
FOLLY_DETAIL_ERROR(ESRMNT),
#endif
#if defined(ESTALE)
FOLLY_DETAIL_ERROR(ESTALE),
#endif
#if defined(ESTRPIPE)
FOLLY_DETAIL_ERROR(ESTRPIPE),
#endif
#if defined(ETIME)
FOLLY_DETAIL_ERROR(ETIME),
#endif
#if defined(ETIMEDOUT)
FOLLY_DETAIL_ERROR(ETIMEDOUT),
#endif
#if defined(ETOOMANYREFS)
FOLLY_DETAIL_ERROR(ETOOMANYREFS),
#endif
#if defined(ETXTBSY)
FOLLY_DETAIL_ERROR(ETXTBSY),
#endif
#if defined(EUCLEAN)
FOLLY_DETAIL_ERROR(EUCLEAN),
#endif
#if defined(EUNATCH)
FOLLY_DETAIL_ERROR(EUNATCH),
#endif
#if defined(EUSERS)
FOLLY_DETAIL_ERROR(EUSERS),
#endif
#if defined(EWOULDBLOCK)
FOLLY_DETAIL_ERROR(EWOULDBLOCK),
#endif
#if defined(EXDEV)
FOLLY_DETAIL_ERROR(EXDEV),
#endif
#if defined(EXFULL)
FOLLY_DETAIL_ERROR(EXFULL),
#endif
};
#undef FOLLY_DETAIL_ERROR
void writeStderr(const char* s, size_t len) {
writeFull(STDERR_FILENO, s, len);
}
void writeStderr(const char* s) {
writeStderr(s, strlen(s));
}
} // namespace
void assertionFailure(
......@@ -36,7 +455,8 @@ void assertionFailure(
const char* msg,
const char* file,
unsigned int line,
const char* function) {
const char* function,
int error) {
writeStderr("\n\nAssertion failure: ");
writeStderr(expr + 1, strlen(expr) - 2);
writeStderr("\nMessage: ");
......@@ -49,6 +469,20 @@ void assertionFailure(
writeFull(STDERR_FILENO, buf, n);
writeStderr("\nFunction: ");
writeStderr(function);
if (error) {
// if errno is set, print the number and the symbolic constant
// the symbolic constant is necessary since actual numbers may vary
// for simplicity, do not attempt to mimic strerror printing descriptions
writeStderr("\nError: ");
n = uint64ToBufferUnsafe(error, buf);
writeFull(STDERR_FILENO, buf, n);
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; };
auto const it = std::find_if(std::begin(errors), std::end(errors), pred);
writeStderr(it != std::end(errors) ? it->second : "<unknown>");
writeStderr(")");
}
writeStderr("\n");
fsyncNoInt(STDERR_FILENO);
abort();
......
......@@ -16,23 +16,28 @@
#pragma once
#include <cerrno>
#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( \
FB_STRINGIZE(expr_s), \
(msg), \
__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_IMPL(expr, expr_s, msg) \
((expr) ? static_cast<void>(0) \
: ::folly::detail::assertionFailure( \
FB_STRINGIZE(expr_s), \
(msg), \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__))
#define FOLLY_SAFE_CHECK(expr, msg) FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg))
#define FOLLY_SAFE_CHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), 0)
/**
* In debug mode, verify that the expression is true. Otherwise, do nothing
......@@ -40,7 +45,13 @@
* only does async-signal-safe calls.
*/
#define FOLLY_SAFE_DCHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL(!::folly::kIsDebug || (expr), (expr), (msg))
FOLLY_SAFE_CHECK_IMPL(!::folly::kIsDebug || (expr), (expr), (msg), 0)
/**
* Like FOLLY_SAFE_CHECK, but also prints errno.
*/
#define FOLLY_SAFE_PCHECK(expr, msg) \
FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), errno)
namespace folly {
namespace detail {
......@@ -50,6 +61,7 @@ namespace detail {
const char* msg,
const char* file,
unsigned int line,
const char* function);
const char* function,
int error);
} // namespace detail
} // namespace folly
......@@ -19,6 +19,7 @@
#include <glog/logging.h>
#include <folly/Benchmark.h>
#include <folly/Conv.h>
#include <folly/portability/GTest.h>
// clang-format off
......@@ -36,3 +37,12 @@ TEST(SafeAssert, AssertionFailure) {
EXPECT_DEATH(fail(), "Assertion failure: 0 \\+ 0");
EXPECT_DEATH(fail(), "Message: hello");
}
TEST(SafeAssert, AssertionFailureErrno) {
EXPECT_DEATH(
FOLLY_SAFE_PCHECK((errno = EINVAL) && false, "hello"),
folly::to<std::string>("Error: ", EINVAL, " \\(EINVAL\\)"));
EXPECT_DEATH(
FOLLY_SAFE_PCHECK((errno = 999) && false, "hello"),
folly::to<std::string>("Error: 999 \\(<unknown>\\)"));
}
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