folly-clib-20260203.1245: folly/folly/lang/SafeAssert.h
/*
* Copyright (c) Meta Platforms, Inc. and 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.
*/
#pragma once
#include <cstdint>
#include <utility>
#include <folly/CppAttributes.h>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#include <folly/lang/CArray.h>
#define FOLLY_DETAIL_SAFE_CHECK_IMPL(d, p, u, expr, ...) \
do { \
if ((!d || ::folly::kIsDebug || ::folly::kIsSanitize) && \
!static_cast<bool>(expr)) { \
static constexpr auto __folly_detail_safe_assert_fun = __func__; \
static constexpr ::folly::detail::safe_assert_arg \
__folly_detail_safe_assert_arg{ \
u ? nullptr : #expr, \
__FILE__, \
FOLLY_PP_CONSTINIT_LINE_UNSIGNED, \
__folly_detail_safe_assert_fun, \
::folly::detail::safe_assert_msg_types< \
decltype(::folly::detail::safe_assert_msg_types_seq_of( \
__VA_ARGS__))>::value.data}; \
constexpr ::folly::detail::safe_assert_terminate_w<p> \
__folly_detail_safe_assert_terminate_w{ \
__folly_detail_safe_assert_arg}; \
__folly_detail_safe_assert_terminate_w(__VA_ARGS__); \
} \
} while (false)
// 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, 0, expr, __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, 0, expr, __VA_ARGS__)
// FOLLY_SAFE_PCHECK
//
// Equivalent to FOLLY_SAFE_CHECK but includes errno in the contextual
// information printed to stderr.
//
// multi-thread-safe
// async-signal-safe
#define FOLLY_SAFE_PCHECK(expr, ...) \
FOLLY_DETAIL_SAFE_CHECK_IMPL(0, 1, 0, expr, __VA_ARGS__)
// FOLLY_SAFE_DPCHECK
//
// Equivalent to FOLLY_SAFE_DCHECK but includes errno in the contextual
// information printed to stderr.
//
// multi-thread-safe
// async-signal-safe
#define FOLLY_SAFE_DPCHECK(expr, ...) \
FOLLY_DETAIL_SAFE_CHECK_IMPL(1, 1, 0, expr, __VA_ARGS__)
// FOLLY_SAFE_FATAL
//
// Equivalent to FOLLY_SAFE_CHECK(false, ...) but excludes any failing
// expression from the contextual information printed to stderr.
//
// multi-thread-safe
// async-signal-safe
#define FOLLY_SAFE_FATAL(...) \
FOLLY_DETAIL_SAFE_CHECK_IMPL(0, 0, 1, false, __VA_ARGS__)
// FOLLY_SAFE_DFATAL
//
// Equivalent to FOLLY_SAFE_DCHECK(false, ...) but excludes any failing
// expression from the contextual information printed to stderr.
//
// multi-thread-safe
// async-signal-safe
#define FOLLY_SAFE_DFATAL(...) \
FOLLY_DETAIL_SAFE_CHECK_IMPL(1, 0, 1, false, __VA_ARGS__)
namespace folly {
namespace detail {
enum class safe_assert_msg_type : char { term, cstr, ui64 };
template <safe_assert_msg_type... A>
struct safe_assert_msg_type_s {};
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;
};
inline constexpr safe_assert_msg_types_one_fn
safe_assert_msg_types_one{}; // a function object to prevent extensions
template <typename... A>
safe_assert_msg_type_s<decltype(safe_assert_msg_types_one((A)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}};
};
struct safe_assert_arg {
char const* expr;
char const* file;
unsigned int line;
char const* function;
safe_assert_msg_type const* msg_types;
};
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; }
};
inline constexpr safe_assert_msg_cast_one_fn
safe_assert_msg_cast_one{}; // a function object to prevent extensions
template <bool P>
[[noreturn, FOLLY_ATTR_GNU_COLD]] FOLLY_NOINLINE void safe_assert_terminate(
safe_assert_arg const* arg, ...) noexcept; // the true backing function
template <bool P>
struct safe_assert_terminate_w {
safe_assert_arg const& arg;
FOLLY_ERASE constexpr safe_assert_terminate_w(
safe_assert_arg const& arg_) noexcept
: arg{arg_} {}
template <typename... A>
[[noreturn]] FOLLY_ERASE void operator()(A... a) const noexcept {
safe_assert_terminate<P>(&arg, safe_assert_msg_cast_one(a)...);
}
};
} // namespace detail
} // namespace folly