From 6a876051b118c86e8bfa51961270055da5948813 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 21 Dec 2022 07:31:39 -0800 Subject: Adds ABSL_UNREACHABLE(), a public symbol to replace ABSL_INTERNAL_UNREACHABLE ABSL_UNREACHABLE() is an unreachable statement. A program which reaches one has undefined behavior, and the compiler may optimize accordingly. The behavior is changed to abort the program in !NDEBUG or ABSL_OPTION_HARDENED modes. PiperOrigin-RevId: 496917150 Change-Id: If036b2d9567933fa266fbcd33f3f98c682ad7f41 --- absl/base/macros.h | 26 +++++---------------- absl/base/optimization.h | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 24 deletions(-) (limited to 'absl/base') diff --git a/absl/base/macros.h b/absl/base/macros.h index 3e085a91..bbf7494f 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h @@ -103,17 +103,11 @@ ABSL_NAMESPACE_END // aborts the program in release mode (when NDEBUG is defined). The // implementation should abort the program as quickly as possible and ideally it // should not be possible to ignore the abort request. -#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \ - ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_INTERNAL_HARDENING_ABORT() \ - do { \ - __builtin_trap(); \ - __builtin_unreachable(); \ +#define ABSL_INTERNAL_HARDENING_ABORT() \ + do { \ + ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \ + ABSL_INTERNAL_UNREACHABLE_IMPL(); \ } while (false) -#else -#define ABSL_INTERNAL_HARDENING_ABORT() abort() -#endif // ABSL_HARDENING_ASSERT() // @@ -144,15 +138,7 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_RETHROW do {} while (false) #endif // ABSL_HAVE_EXCEPTIONS -// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which -// reaches one has undefined behavior, and the compiler may optimize -// accordingly. -#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) -#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -#define ABSL_INTERNAL_UNREACHABLE __assume(0) -#else -#define ABSL_INTERNAL_UNREACHABLE -#endif +// TODO(b/261916195): Replace ABSL_INTERNAL_UNREACHABLE with ABSL_UNREACHABLE(). +#define ABSL_INTERNAL_UNREACHABLE ABSL_UNREACHABLE() #endif // ABSL_BASE_MACROS_H_ diff --git a/absl/base/optimization.h b/absl/base/optimization.h index d706100c..04870cba 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h @@ -181,6 +181,52 @@ #define ABSL_PREDICT_TRUE(x) (x) #endif +// `ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL()` aborts the program in the fastest +// possible way, with no attempt at logging. One use is to implement hardening +// aborts with ABSL_OPTION_HARDENED. Since this is an internal symbol, it +// should not be used directly outside of Abseil. +#if ABSL_HAVE_BUILTIN(__builtin_trap) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() __builtin_trap() +#else +#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() abort() +#endif + +// `ABSL_INTERNAL_UNREACHABLE_IMPL()` is the platform specific directive to +// indicate that a statement is unreachable, and to allow the compiler to +// optimize accordingly. Clients should use `ABSL_UNREACHABLE()`, which is +// defined below. +#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L +#define ABSL_INTERNAL_UNREACHABLE_IMPL() std::unreachable() +#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_unreachable() +#elif ABSL_HAVE_BUILTIN(__builtin_assume) +#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_assume(false) +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_UNREACHABLE_IMPL() __assume(false) +#else +#define ABSL_INTERNAL_UNREACHABLE_IMPL() +#endif + +// `ABSL_UNREACHABLE()` is an unreachable statement. A program which reaches +// one has undefined behavior, and the compiler may optimize accordingly. +#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG) +// Abort in hardened mode to avoid dangerous undefined behavior. +#define ABSL_UNREACHABLE() \ + do { \ + ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \ + ABSL_INTERNAL_UNREACHABLE_IMPL(); \ + } while (false) +#else +// The assert only fires in debug mode to aid in debugging. +// When NDEBUG is defined, reaching ABSL_UNREACHABLE() is undefined behavior. +#define ABSL_UNREACHABLE() \ + do { \ + assert(false && "ABSL_UNREACHABLE reached"); \ + ABSL_INTERNAL_UNREACHABLE_IMPL(); \ + } while (false) +#endif + // ABSL_ASSUME(cond) // // Informs the compiler that a condition is always true and that it can assume @@ -209,18 +255,23 @@ #define ABSL_ASSUME(cond) assert(cond) #elif ABSL_HAVE_BUILTIN(__builtin_assume) #define ABSL_ASSUME(cond) __builtin_assume(cond) +#elif defined(_MSC_VER) +#define ABSL_ASSUME(cond) __assume(cond) +#elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L +#define ABSL_ASSUME(cond) \ + do { \ + if (!(cond)) std::unreachable(); \ + } while (false) #elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) #define ABSL_ASSUME(cond) \ do { \ if (!(cond)) __builtin_unreachable(); \ - } while (0) -#elif defined(_MSC_VER) -#define ABSL_ASSUME(cond) __assume(cond) + } while (false) #else #define ABSL_ASSUME(cond) \ do { \ static_cast(false && (cond)); \ - } while (0) + } while (false) #endif // ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond) -- cgit v1.2.3