summaryrefslogtreecommitdiff
path: root/absl/base
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base')
-rw-r--r--absl/base/internal/spinlock.cc19
-rw-r--r--absl/base/internal/spinlock.h13
-rw-r--r--absl/base/macros.h35
-rw-r--r--absl/base/options.h33
4 files changed, 82 insertions, 18 deletions
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 830d4729..fd0c733e 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -190,30 +190,32 @@ void SpinLock::SlowUnlock(uint32_t lock_value) {
// We use the upper 29 bits of the lock word to store the time spent waiting to
// acquire this lock. This is reported by contentionz profiling. Since the
// lower bits of the cycle counter wrap very quickly on high-frequency
-// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT
+// processors we divide to reduce the granularity to 2^kProfileTimestampShift
// sized units. On a 4Ghz machine this will lose track of wait times greater
// than (2^29/4 Ghz)*128 =~ 17.2 seconds. Such waits should be extremely rare.
-enum { PROFILE_TIMESTAMP_SHIFT = 7 };
-enum { LOCKWORD_RESERVED_SHIFT = 3 }; // We currently reserve the lower 3 bits.
+static constexpr int kProfileTimestampShift = 7;
+
+// We currently reserve the lower 3 bits.
+static constexpr int kLockwordReservedShift = 3;
uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
int64_t wait_end_time) {
static const int64_t kMaxWaitTime =
- std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT;
+ std::numeric_limits<uint32_t>::max() >> kLockwordReservedShift;
int64_t scaled_wait_time =
- (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
+ (wait_end_time - wait_start_time) >> kProfileTimestampShift;
// Return a representation of the time spent waiting that can be stored in
// the lock word's upper bits.
uint32_t clamped = static_cast<uint32_t>(
- std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
+ std::min(scaled_wait_time, kMaxWaitTime) << kLockwordReservedShift);
if (clamped == 0) {
return kSpinLockSleeper; // Just wake waiters, but don't record contention.
}
// Bump up value if necessary to avoid returning kSpinLockSleeper.
const uint32_t kMinWaitTime =
- kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
+ kSpinLockSleeper + (1 << kLockwordReservedShift);
if (clamped == kSpinLockSleeper) {
return kMinWaitTime;
}
@@ -224,8 +226,7 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
// Cast to uint32_t first to ensure bits [63:32] are cleared.
const uint64_t scaled_wait_time =
static_cast<uint32_t>(lock_value & kWaitTimeMask);
- return scaled_wait_time
- << (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT);
+ return scaled_wait_time << (kProfileTimestampShift - kLockwordReservedShift);
}
} // namespace base_internal
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 24e2e9a6..89e93aad 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -148,12 +148,13 @@ class ABSL_LOCKABLE SpinLock {
// bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether a lock disables scheduling.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
- enum { kSpinLockHeld = 1 };
- enum { kSpinLockCooperative = 2 };
- enum { kSpinLockDisabledScheduling = 4 };
- enum { kSpinLockSleeper = 8 };
- enum { kWaitTimeMask = // Includes kSpinLockSleeper.
- ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) };
+ static constexpr uint32_t kSpinLockHeld = 1;
+ static constexpr uint32_t kSpinLockCooperative = 2;
+ static constexpr uint32_t kSpinLockDisabledScheduling = 4;
+ static constexpr uint32_t kSpinLockSleeper = 8;
+ // Includes kSpinLockSleeper.
+ static constexpr uint32_t kWaitTimeMask =
+ ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
// Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative(
diff --git a/absl/base/macros.h b/absl/base/macros.h
index 547f93ba..2f6089f4 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -32,6 +32,7 @@
#include <cstddef>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
@@ -207,6 +208,40 @@ ABSL_NAMESPACE_END
: [] { assert(false && #expr); }()) // NOLINT
#endif
+// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
+// 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) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_HARDENING_ABORT() \
+ do { \
+ __builtin_trap(); \
+ __builtin_unreachable(); \
+ } while (false)
+#else
+#define ABSL_INTERNAL_HARDENING_ABORT() abort()
+#endif
+
+// ABSL_HARDENING_ASSERT()
+//
+// `ABSL_HARDENED_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
+// runtime assertions that should be enabled in hardened builds even when
+// `NDEBUG` is defined.
+//
+// When `NDEBUG` is not defined, `ABSL_HARDENED_ASSERT()` is identical to
+// `ABSL_ASSERT()`.
+//
+// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
+// hardened mode.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#define ABSL_HARDENING_ASSERT(expr) \
+ (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+ : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
+#else
+#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
+#endif
+
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
diff --git a/absl/base/options.h b/absl/base/options.h
index 234137c7..230bf1ee 100644
--- a/absl/base/options.h
+++ b/absl/base/options.h
@@ -1,6 +1,3 @@
-#ifndef ABSL_BASE_OPTIONS_H_
-#define ABSL_BASE_OPTIONS_H_
-
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,6 +64,9 @@
// proper Abseil implementation at compile-time, which will not be sufficient
// to guarantee ABI stability to package managers.
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_OPTIONS_H_
+
// Include a standard library header to allow configuration based on the
// standard library in use.
#ifdef __cplusplus
@@ -208,4 +208,31 @@
#define ABSL_OPTION_USE_INLINE_NAMESPACE 0
#define ABSL_OPTION_INLINE_NAMESPACE_NAME head
+// ABSL_OPTION_HARDENED
+//
+// This option enables a "hardened" build in release mode (in this context,
+// release mode is defined as a build where the `NDEBUG` macro is defined).
+//
+// A value of 0 means that "hardened" mode is not enabled.
+//
+// A value of 1 means that "hardened" mode is enabled.
+//
+// Hardened builds have additional security checks enabled when `NDEBUG` is
+// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
+// no-op, as well as disabling other bespoke program consistency checks. By
+// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
+// release mode. These checks guard against programming errors that may lead to
+// security vulnerabilities. In release mode, when one of these programming
+// errors is encountered, the program will immediately abort, possibly without
+// any attempt at logging.
+//
+// The checks enabled by this option are not free; they do incur runtime cost.
+//
+// The checks enabled by this option are always active when `NDEBUG` is not
+// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
+// checks enabled by this option may abort the program in a different way and
+// log additional information when `NDEBUG` is not defined.
+
+#define ABSL_OPTION_HARDENED 0
+
#endif // ABSL_BASE_OPTIONS_H_