diff --git a/folly/lang/SafeAssert.cpp b/folly/lang/SafeAssert.cpp
index 742bfd25036eb21a26c9b40d7bda21a8cb9f5375..4339cac7e81357f10cf7ece95834c1d6cba5777e 100644
--- a/folly/lang/SafeAssert.cpp
+++ b/folly/lang/SafeAssert.cpp
@@ -17,12 +17,15 @@
 #include <folly/lang/SafeAssert.h>
 
 #include <algorithm>
+#include <cerrno>
+#include <cstdarg>
 
 #include <folly/detail/FileUtilDetail.h>
 #include <folly/lang/ToAscii.h>
 #include <folly/portability/Unistd.h>
 
 namespace folly {
+namespace detail {
 
 namespace {
 
@@ -441,48 +444,53 @@ 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);
 }
 
-void writeStderr(unsigned long x) {
+[[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(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(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(file);
+  writeStderr(arg.file);
   writeStderr("\nLine: ");
-  writeStderr(line);
+  writeStderr(buf, to_ascii_decimal(buf, arg.line));
   writeStderr("\nFunction: ");
-  writeStderr(function);
+  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(error);
+    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; };
@@ -495,5 +503,23 @@ void writeErrBegin(const char* expr, const char* msg) {
   abort();
 }
 
-} // namespace signal_safe
+} // 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
diff --git a/folly/lang/SafeAssert.h b/folly/lang/SafeAssert.h
index 18dd02446661bf59ddead2ec983326425d765eab..e976e757b3c3e377eb8d4754647510601f1046af 100644
--- a/folly/lang/SafeAssert.h
+++ b/folly/lang/SafeAssert.h
@@ -16,58 +16,130 @@
 
 #pragma once
 
-#include <cerrno>
+#include <cstdint>
+#include <utility>
 
+#include <folly/CppAttributes.h>
 #include <folly/Portability.h>
 #include <folly/Preprocessor.h>
+#include <folly/lang/CArray.h>
 
-#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, __VA_ARGS__);
+#define FOLLY_DETAIL_SAFE_CHECK_IMPL(d, p, expr, expr_s, ...)                  \
+  if ((!d || ::folly::kIsDebug || ::folly::kIsSanitize) &&                     \
+      !static_cast<bool>(expr)) {                                              \
+    static constexpr auto __folly_detail_safe_assert_arg =                     \
+        ::folly::detail::safe_assert_arg{                                      \
+            FOLLY_PP_STRINGIZE(expr_s),                                        \
+            __FILE__,                                                          \
+            __LINE__,                                                          \
+            __PRETTY_FUNCTION__,                                               \
+            ::folly::detail::safe_assert_msg_types_ptr<decltype(               \
+                ::folly::detail::safe_assert_msg_types_seq_of(__VA_ARGS__))>}; \
+    ::folly::detail::safe_assert_terminate<p>(                                 \
+        __folly_detail_safe_assert_arg, __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, __VA_ARGS__)
+//  FOLLY_SAFE_CHECK
+//
+//  If expr evaluates to false after explicit conversion to bool, prints context
+//  information to stderr and aborts. Context information includes the remaining
+//  variadic arguments.
+//
+//  When the remaining variadic arguments are printed to stderr, there are two
+//  supported types after implicit conversions: char const* and uint64_t. This
+//  facility is intentionally not extensible to custom types.
+//
+//  multi-thread-safe
+//  async-signal-safe
+#define FOLLY_SAFE_CHECK(expr, ...) \
+  FOLLY_DETAIL_SAFE_CHECK_IMPL(     \
+      0, 0, (expr), FOLLY_PP_STRINGIZE(expr), __VA_ARGS__)
 
-/**
- * Like FOLLY_SAFE_CHECK, but also prints errno.
- */
-#define FOLLY_SAFE_PCHECK(expr, msg, ...) \
-  FOLLY_SAFE_CHECK_IMPL((expr), (expr), (msg), errno, __VA_ARGS__)
+//  FOLLY_SAFE_DCHECK
+//
+//  Equivalent to FOLLY_SAFE_CHECK when in debug or instrumented builds, where
+//  debug builds are signalled by NDEBUG being undefined and instrumented builds
+//  include sanitizer builds.
+//
+//  multi-thread-safe
+//  async-signal-safe
+#define FOLLY_SAFE_DCHECK(expr, ...) \
+  FOLLY_DETAIL_SAFE_CHECK_IMPL(      \
+      1, 0, (expr), FOLLY_PP_STRINGIZE(expr), __VA_ARGS__)
+
+//  FOLLY_SAFE_PCHECK
+//
+//  Equivalent to FOLLY_SAFE_CHECK but includes errno in the context information
+//  printed to stderr.
+//
+//  multi-thread-safe
+//  async-signal-safe
+#define FOLLY_SAFE_PCHECK(expr, ...) \
+  FOLLY_DETAIL_SAFE_CHECK_IMPL(      \
+      0, 1, (expr), FOLLY_PP_STRINGIZE(expr), __VA_ARGS__)
 
 namespace folly {
-namespace signal_safe {
+namespace detail {
+
+enum class safe_assert_msg_type : char { term, cstr, ui64 };
+
+template <safe_assert_msg_type... A>
+struct safe_assert_msg_type_s {};
 
-void writeStderr(const char*);
-void writeStderr(unsigned long int);
+struct safe_assert_msg_types_one_fn {
+  template <safe_assert_msg_type A>
+  using c = std::integral_constant<safe_assert_msg_type, A>;
+  // only used in unevaluated contexts:
+  c<safe_assert_msg_type::cstr> operator()(char const*) const;
+  c<safe_assert_msg_type::ui64> operator()(uint64_t) const;
+};
+FOLLY_INLINE_VARIABLE constexpr safe_assert_msg_types_one_fn
+    safe_assert_msg_types_one{}; // a function object to prevent extensions
 
 template <typename... A>
-void writeStderrPack(A... a) {
-  // NOTE: C++14-compatible version of comma fold expression.
-  using _ = int[];
-  void(_{0, (writeStderr(a), 0)...});
-}
+safe_assert_msg_type_s<decltype(safe_assert_msg_types_one(A{}))::value...>
+safe_assert_msg_types_seq_of(A...); // only used in unevaluated contexts
+
+template <typename>
+struct safe_assert_msg_types;
+template <safe_assert_msg_type... A>
+struct safe_assert_msg_types<safe_assert_msg_type_s<A...>> {
+  using value_type = c_array<safe_assert_msg_type, sizeof...(A) + 1>;
+  static constexpr value_type value = {{A..., safe_assert_msg_type::term}};
+};
+template <safe_assert_msg_type... A>
+constexpr
+    typename safe_assert_msg_types<safe_assert_msg_type_s<A...>>::value_type
+        safe_assert_msg_types<safe_assert_msg_type_s<A...>>::value;
+template <typename S>
+static constexpr safe_assert_msg_type const* safe_assert_msg_types_ptr =
+    safe_assert_msg_types<S>::value.data;
+
+struct safe_assert_arg {
+  char const* expr;
+  char const* file;
+  unsigned int line;
+  char const* function;
+  safe_assert_msg_type const* msg_types;
+};
 
-void writeErrBegin(const char* expr, const char* msg);
-[[noreturn]] void writeErrEnd(
-    const char* file, unsigned int line, const char* function, int error);
+struct safe_assert_msg_cast_one_fn {
+  FOLLY_ERASE auto operator()(char const* const a) const { return a; }
+  FOLLY_ERASE auto operator()(uint64_t const a) const { return a; }
+};
+FOLLY_INLINE_VARIABLE constexpr safe_assert_msg_cast_one_fn
+    safe_assert_msg_cast_one{}; // a function object to prevent extensions
+
+template <bool P>
+[[noreturn]] FOLLY_COLD FOLLY_NOINLINE void safe_assert_terminate(
+    safe_assert_arg const* arg, ...) noexcept; // the true backing function
+
+template <bool P, typename... A>
+[[noreturn]] FOLLY_ERASE void safe_assert_terminate(
+    safe_assert_arg const& arg, A... a) noexcept {
+  safe_assert_terminate<P>(&arg, safe_assert_msg_cast_one(a)...);
+}
 
-} // namespace signal_safe
+} // namespace detail
 } // namespace folly
diff --git a/folly/lang/test/SafeAssertTest.cpp b/folly/lang/test/SafeAssertTest.cpp
index 664bbe9b7658d75244038b7dcfb81cd9a8879f03..ff2b6ce9a548f07bdd2f2bcd9e5f658badea936a 100644
--- a/folly/lang/test/SafeAssertTest.cpp
+++ b/folly/lang/test/SafeAssertTest.cpp
@@ -53,9 +53,9 @@ TEST(SafeAssert, AssertionFailure) {
 
 TEST(SafeAssert, AssertionFailureErrno) {
   EXPECT_DEATH(
-      FOLLY_SAFE_PCHECK((errno = EINVAL) && false, "hello"),
+      ([] { FOLLY_SAFE_PCHECK((errno = EINVAL) && false, "hello"); }()),
       folly::to<std::string>("Error: ", EINVAL, " \\(EINVAL\\)"));
   EXPECT_DEATH(
-      FOLLY_SAFE_PCHECK((errno = 999) && false, "hello"),
+      ([] { FOLLY_SAFE_PCHECK((errno = 999) && false, "hello"); }()),
       folly::to<std::string>("Error: 999 \\(<unknown>\\)"));
 }