/* * Copyright 2006 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef RTC_BASE_CHECKS_H_ #define RTC_BASE_CHECKS_H_ // If you for some reson need to know if DCHECKs are on, test the value of // RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be // defined, to either a true or a false value.) #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) #define RTC_DCHECK_IS_ON … #else #define RTC_DCHECK_IS_ON … #endif // Annotate a function that will not return control flow to the caller. #if defined(_MSC_VER) #define RTC_NORETURN … #elif defined(__GNUC__) #define RTC_NORETURN … #else #define RTC_NORETURN #endif #ifdef __cplusplus extern "C" { #endif RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); #ifdef __cplusplus } // extern "C" #endif #ifdef RTC_DISABLE_CHECK_MSG #define RTC_CHECK_MSG_ENABLED … #else #define RTC_CHECK_MSG_ENABLED … #endif #if RTC_CHECK_MSG_ENABLED #define RTC_CHECK_EVAL_MESSAGE(message) … #else #define RTC_CHECK_EVAL_MESSAGE … #endif #ifdef __cplusplus // C++ version. #include <string> #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" #include "api/scoped_refptr.h" #include "rtc_base/numerics/safe_compare.h" #include "rtc_base/system/inline.h" #include "rtc_base/system/rtc_export.h" // The macros here print a message to stderr and abort under various // conditions. All will accept additional stream messages. For example: // RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar."; // // - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't, // it's better to terminate the process than to continue. During development, // the reason that it's better to terminate might simply be that the error // handling code isn't in place yet; in production, the reason might be that // the author of the code truly believes that x will always be true, but that // they recognizes that if they are wrong, abrupt and unpleasant process // termination is still better than carrying on with the assumption violated. // // RTC_CHECK always evaluates its argument, so it's OK for x to have side // effects. // // - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always // true---except that x will only be evaluated in debug builds; in production // builds, x is simply assumed to be true. This is useful if evaluating x is // expensive and the expected cost of failing to detect the violated // assumption is acceptable. You should not handle cases where a production // build fails to spot a violated condition, even those that would result in // crashes. If the code needs to cope with the error, make it cope, but don't // call RTC_DCHECK; if the condition really can't occur, but you'd sleep // better at night knowing that the process will suicide instead of carrying // on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK. // // RTC_DCHECK only evaluates its argument in debug builds, so if x has visible // side effects, you need to write e.g. // bool w = x; RTC_DCHECK(w); // // - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are // specialized variants of RTC_CHECK and RTC_DCHECK that print prettier // messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and // RTC_DCHECK. // // - RTC_FATAL() aborts unconditionally. namespace rtc { namespace webrtc_checks_impl { enum class CheckArgType : int8_t { … }; // These two functions are public so they can be overridden from // webrtc_overrides in chromium. RTC_NORETURN void WriteFatalLog(const char* file, int line, absl::string_view output); RTC_NORETURN void WriteFatalLog(absl::string_view output); #if RTC_CHECK_MSG_ENABLED RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line, const char* message, const CheckArgType* fmt, ...); #else RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line); #endif // Wrapper for log arguments. Only ever make values of this type with the // MakeVal() functions. template <CheckArgType N, typename T> struct Val { … }; // Case for when we need to construct a temp string and then print that. // (We can't use Val<CheckArgType::kStdString, const std::string*> // because we need somewhere to store the temp string.) struct ToStringVal { … }; inline Val<CheckArgType::kInt, int> MakeVal(int x) { … } inline Val<CheckArgType::kLong, long> MakeVal(long x) { … } inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) { … } inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) { … } inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) { … } inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal( unsigned long long x) { … } inline Val<CheckArgType::kDouble, double> MakeVal(double x) { … } inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) { … } inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) { … } inline Val<CheckArgType::kStdString, const std::string*> MakeVal( const std::string& x) { … } inline Val<CheckArgType::kStringView, const absl::string_view*> MakeVal( const absl::string_view& x) { … } inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) { … } template <typename T> inline Val<CheckArgType::kVoidP, const void*> MakeVal( const rtc::scoped_refptr<T>& p) { … } // The enum class types are not implicitly convertible to arithmetic types. template <typename T, absl::enable_if_t<std::is_enum<T>::value && !std::is_arithmetic<T>::value>* = nullptr> inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal( T x) { … } template <typename T, decltype(ToLogString(std::declval<T>()))* = nullptr> ToStringVal MakeVal(const T& x) { … } // Ephemeral type that represents the result of the logging << operator. template <typename... Ts> class LogStreamer; // Base case: Before the first << argument. template <> class LogStreamer<> final { … }; // Inductive case: We've already seen at least one << argument. The most recent // one had type `T`, and the earlier ones had types `Ts`. LogStreamer<T, Ts...>; template <bool isCheckOp> class FatalLogCall final { … }; #if RTC_DCHECK_IS_ON // Be helpful, and include file and line in the RTC_CHECK_NOTREACHED error // message. #define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS … RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(const char* file, int line); #else // Be mindful of binary size, and don't include file and line in the // RTC_CHECK_NOTREACHED error message. #define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(); #endif } // namespace webrtc_checks_impl // The actual stream used isn't important. We reference `ignored` in the code // but don't evaluate it; this is to avoid "unused variable" warnings (we do so // in a particularly convoluted way with an extra ?: because that appears to be // the simplest construct that keeps Visual Studio from complaining about // condition being unused). #define RTC_EAT_STREAM_PARAMETERS(ignored) … // Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if // values of the same types as `a` and `b` can't be compared with the given // operation, and that would evaluate `a` and `b` if evaluated. #define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) … // RTC_CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG or anything else, so the check will be executed // regardless of compilation mode. // // We make sure RTC_CHECK et al. always evaluates `condition`, as // doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom. // // RTC_CHECK_OP is a helper macro for binary operators. // Don't use this macro directly in your code, use RTC_CHECK_EQ et al below. #if RTC_CHECK_MSG_ENABLED #define RTC_CHECK(condition) … #define RTC_CHECK_OP(name, op, val1, val2) … #else #define RTC_CHECK … #define RTC_CHECK_OP … #endif #define RTC_CHECK_EQ(val1, val2) … #define RTC_CHECK_NE(val1, val2) … #define RTC_CHECK_LE(val1, val2) … #define RTC_CHECK_LT(val1, val2) … #define RTC_CHECK_GE(val1, val2) … #define RTC_CHECK_GT(val1, val2) … // The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates // code in debug builds. It does reference the condition parameter in all cases, // though, so callers won't risk getting warnings about unused variables. #if RTC_DCHECK_IS_ON #define RTC_DCHECK(condition) … #define RTC_DCHECK_EQ(v1, v2) … #define RTC_DCHECK_NE(v1, v2) … #define RTC_DCHECK_LE(v1, v2) … #define RTC_DCHECK_LT(v1, v2) … #define RTC_DCHECK_GE(v1, v2) … #define RTC_DCHECK_GT(v1, v2) … #else #define RTC_DCHECK … #define RTC_DCHECK_EQ … #define RTC_DCHECK_NE … #define RTC_DCHECK_LE … #define RTC_DCHECK_LT … #define RTC_DCHECK_GE … #define RTC_DCHECK_GT … #endif #define RTC_UNREACHABLE_CODE_HIT … #define RTC_DCHECK_NOTREACHED() … // Kills the process with an error message. Never returns. Use when you wish to // assert that a point in the code is never reached. #define RTC_CHECK_NOTREACHED() … #define RTC_FATAL() … // Performs the integer division a/b and returns the result. CHECKs that the // remainder is zero. template <typename T> inline T CheckedDivExact(T a, T b) { … } } // namespace rtc #else // __cplusplus not defined // C version. Lacks many features compared to the C++ version, but usage // guidelines are the same. #define RTC_CHECK … #define RTC_CHECK_EQ … #define RTC_CHECK_NE … #define RTC_CHECK_LE … #define RTC_CHECK_LT … #define RTC_CHECK_GE … #define RTC_CHECK_GT … #define RTC_DCHECK … #define RTC_DCHECK_EQ … #define RTC_DCHECK_NE … #define RTC_DCHECK_LE … #define RTC_DCHECK_LT … #define RTC_DCHECK_GE … #define RTC_DCHECK_GT … #endif // __cplusplus #endif // RTC_BASE_CHECKS_H_