588 lines
13 KiB
C++
588 lines
13 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* 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 <folly/lang/SafeAssert.h>
|
|
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <cstdarg>
|
|
|
|
#include <folly/detail/FileUtilDetail.h>
|
|
#include <folly/lang/ToAscii.h>
|
|
#include <folly/portability/SysTypes.h>
|
|
#include <folly/portability/Windows.h>
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <fileapi.h> // @manual
|
|
|
|
#else
|
|
|
|
// @lint-ignore CLANGTIDY
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
// This header takes care to have minimal dependencies.
|
|
|
|
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
|
|
|
|
#if defined(_WIN32)
|
|
|
|
constexpr int stderr_fileno = 2;
|
|
|
|
ssize_t write(int fh, void const* buf, size_t count) {
|
|
auto r = _write(fh, buf, static_cast<unsigned int>(count));
|
|
if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) {
|
|
// Writing to a pipe with a full buffer doesn't generate
|
|
// any error type, unless it caused us to write exactly 0
|
|
// bytes, so we have to see if we have a pipe first. We
|
|
// don't touch the errno for anything else.
|
|
HANDLE h = (HANDLE)_get_osfhandle(fh);
|
|
if (GetFileType(h) == FILE_TYPE_PIPE) {
|
|
DWORD state = 0;
|
|
if (GetNamedPipeHandleState(
|
|
h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
|
|
if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
|
|
errno = EAGAIN;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int fsync(int fh) {
|
|
HANDLE h = (HANDLE)_get_osfhandle(fh);
|
|
if (!FlushFileBuffers(h)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
constexpr int stderr_fileno = STDERR_FILENO;
|
|
|
|
#endif
|
|
|
|
#if !defined(_WIN32) && !defined(_POSIX_FSYNC)
|
|
|
|
int fsync(int fh) {
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
|
|
[[noreturn]] FOLLY_COLD void safe_assert_terminate_v(
|
|
safe_assert_arg const* arg_, int const error, va_list msg) noexcept {
|
|
auto const& arg = *arg_;
|
|
char buf[to_ascii_size_max_decimal<uint64_t>];
|
|
|
|
writeStderr("\n\nAssertion failure: ");
|
|
writeStderr(arg.expr + 1, strlen(arg.expr) - 2);
|
|
if (*arg.msg_types != safe_assert_msg_type::term) {
|
|
writeStderr("\nMessage: ");
|
|
auto msg_types = arg.msg_types;
|
|
bool stop = false;
|
|
while (!stop) {
|
|
switch (*msg_types++) {
|
|
case safe_assert_msg_type::term:
|
|
stop = true;
|
|
break;
|
|
case safe_assert_msg_type::cstr:
|
|
writeStderr(va_arg(msg, char const*));
|
|
break;
|
|
case safe_assert_msg_type::ui64:
|
|
writeStderr(buf, to_ascii_decimal(buf, va_arg(msg, uint64_t)));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
writeStderr("\nFile: ");
|
|
writeStderr(arg.file);
|
|
writeStderr("\nLine: ");
|
|
writeStderr(buf, to_ascii_decimal(buf, arg.line));
|
|
writeStderr("\nFunction: ");
|
|
writeStderr(arg.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: ");
|
|
writeStderr(buf, to_ascii_decimal(buf, 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; };
|
|
auto const it = std::find_if(std::begin(errors), std::end(errors), pred);
|
|
writeStderr(it != std::end(errors) ? it->second : "<unknown>");
|
|
writeStderr(")");
|
|
}
|
|
writeStderr("\n");
|
|
flushStderr();
|
|
abort();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
template <>
|
|
void safe_assert_terminate<0>(safe_assert_arg const* arg, ...) noexcept {
|
|
va_list msg;
|
|
va_start(msg, arg);
|
|
safe_assert_terminate_v(arg, 0, msg);
|
|
va_end(msg);
|
|
}
|
|
|
|
template <>
|
|
void safe_assert_terminate<1>(safe_assert_arg const* arg, ...) noexcept {
|
|
va_list msg;
|
|
va_start(msg, arg);
|
|
safe_assert_terminate_v(arg, errno, msg);
|
|
va_end(msg);
|
|
}
|
|
|
|
} // namespace detail
|
|
} // namespace folly
|