diff --git a/absl/base/optimization.h b/absl/base/optimization.h index 6fe03c43..db5cc097 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h @@ -181,32 +181,21 @@ #define ABSL_PREDICT_TRUE(x) (x) #endif -// Platform and compilation mode dependent implementation of ABSL_ASSUME. -#if !defined(NDEBUG) -#define ABSL_INTERNAL_ASSUME(cond) assert(cond) -#elif ABSL_HAVE_BUILTIN(__builtin_assume) -#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond) -#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) -#define ABSL_INTERNAL_ASSUME(cond) \ - do { \ - if (!(cond)) __builtin_unreachable(); \ - } while (0) -#elif defined(_MSC_VER) -#define ABSL_INTERNAL_ASSUME(cond) __assume(cond) -#else -#define ABSL_INTERNAL_ASSUME(cond) \ - do { \ - static_cast(false && (cond)); \ - } while (0) -#endif - // ABSL_ASSUME(cond) +// // Informs the compiler that a condition is always true and that it can assume -// it to be true for optimization purposes. The call has undefined behavior if -// the condition is false. +// it to be true for optimization purposes. +// +// WARNING: If the condition is false, the program can produce undefined and +// potentially dangerous behavior. +// // In !NDEBUG mode, the condition is checked with an assert(). +// // NOTE: The expression must not have side effects, as it may only be evaluated -// in some compilation modes and not others. +// in some compilation modes and not others. Some compilers may issue a warning +// if the compiler cannot prove the expression has no side effects. For example, +// the expression should not use a function call since the compiler cannot prove +// that a function call does not have side effects. // // Example: // @@ -216,7 +205,23 @@ // // assumption specified above. // int y = x / 16; // -#define ABSL_ASSUME(cond) ABSL_INTERNAL_ASSUME(cond) +#if !defined(NDEBUG) +#define ABSL_ASSUME(cond) assert(cond) +#elif ABSL_HAVE_BUILTIN(__builtin_assume) +#define ABSL_ASSUME(cond) __builtin_assume(cond) +#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) +#else +#define ABSL_ASSUME(cond) \ + do { \ + static_cast(false && (cond)); \ + } while (0) +#endif // ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond) // This macro forces small unique name on a static file level symbols like diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h index 83c71029..13779eda 100644 --- a/absl/container/flat_hash_map.h +++ b/absl/container/flat_hash_map.h @@ -76,6 +76,10 @@ struct FlatHashMapPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // +// Using `absl::flat_hash_map` at interface boundries in dynamically loaded +// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may +// be randomized across dynamically loaded libraries. +// // NOTE: A `flat_hash_map` stores its value types directly inside its // implementation array to avoid memory indirection. Because a `flat_hash_map` // is designed to move data when rehashed, map values will not retain pointer diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h index 0fb2ae6f..304c2abb 100644 --- a/absl/container/flat_hash_set.h +++ b/absl/container/flat_hash_set.h @@ -72,6 +72,10 @@ struct FlatHashSetPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // +// Using `absl::flat_hash_set` at interface boundries in dynamically loaded +// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may +// be randomized across dynamically loaded libraries. +// // NOTE: A `flat_hash_set` stores its keys directly inside its implementation // array to avoid memory indirection. Because a `flat_hash_set` is designed to // move data when rehashed, set keys will not retain pointer stability. If you diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h index ca1ed408..f2175d16 100644 --- a/absl/container/node_hash_map.h +++ b/absl/container/node_hash_map.h @@ -78,6 +78,10 @@ class NodeHashMapPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // +// Using `absl::node_hash_map` at interface boundries in dynamically loaded +// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may +// be randomized across dynamically loaded libraries. +// // Example: // // // Create a node hash map of three strings (that map to strings) diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h index 9421e11e..a9ff7e1b 100644 --- a/absl/container/node_hash_set.h +++ b/absl/container/node_hash_set.h @@ -74,6 +74,10 @@ struct NodeHashSetPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // +// Using `absl::node_hash_set` at interface boundries in dynamically loaded +// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may +// be randomized across dynamically loaded libraries. +// // Example: // // // Create a node hash set of three strings diff --git a/absl/hash/hash.h b/absl/hash/hash.h index f31fde40..74e2d7c0 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h @@ -40,6 +40,11 @@ // each process. E.g., `absl::Hash{}(9)` in one process and // `absl::Hash{}(9)` in another process are likely to differ. // +// `absl::Hash` may also produce different values from different dynamically +// loaded libraries. For this reason, `absl::Hash` values must never cross +// boundries in dynamically loaded libraries (including when used in types like +// hash containers.) +// // `absl::Hash` is intended to strongly mix input bits with a target of passing // an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect). //