Export of internal Abseil changes
-- 79913a12f0cad4baf948430315aabf53f03b6475 by Abseil Team <absl-team@google.com>: Don't inline (Un)LockSlow. PiperOrigin-RevId: 302502344 -- 6b340e80f0690655f24799c8de6707b3a95b8579 by Derek Mauro <dmauro@google.com>: Add hardening assertions to absl::optional's dereference operators PiperOrigin-RevId: 302492862 -- a9951bf4852d8c1aec472cb4b539830411270e4c by Derek Mauro <dmauro@google.com>: Correctly add hardware AES compiler flags under Linux X86-64 Fixes #643 PiperOrigin-RevId: 302490673 -- 314c3621ee4d57b6bc8d64338a1f1d48a69741d1 by Derek Mauro <dmauro@google.com>: Upgrade to hardening assertions in absl::Span::remove_prefix and absl::Span::remove_suffix PiperOrigin-RevId: 302481191 -- a142b8c6c62705c5f0d4fe3113150f0c0b7822b9 by Derek Mauro <dmauro@google.com>: Update docker containers to Bazel 2.2.0, GCC 9.3, and new Clang snapshot PiperOrigin-RevId: 302454042 -- afedeb70a2adc87010030c9ba6f06fe35ec26407 by Derek Mauro <dmauro@google.com>: Add hardening assertions for the preconditions of absl::FixedArray PiperOrigin-RevId: 302441767 -- 44442bfbc0a9a742df32f07cee86a47712efb8b4 by Derek Mauro <dmauro@google.com>: Fix new Clang warning about SpinLock doing operations on enums of different types PiperOrigin-RevId: 302430387 -- 69eaff7f97231779f696321c2ba8b88debf6dd9e by Derek Mauro <dmauro@google.com>: Convert precondition assertions to ABSL_HARDENING_ASSERT for absl::InlinedVector PiperOrigin-RevId: 302427894 -- 26b6db906a0942fd18583dc2cdd1bab32919d964 by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 302425283 -- e62e81422979e922505d2cd9000e1de58123c088 by Derek Mauro <dmauro@google.com>: Add an option to build Abseil in hardened mode In hardened mode, the ABSL_HARDENING_ASSERT() macro is active even when NDEBUG is defined. This allows Abseil to perform runtime checks even in release mode. This should be used to implement things like bounds checks that could otherwise lead to security vulnerabilities. Use the new assertion in absl::string_view and absl::Span to test it. PiperOrigin-RevId: 302119187 GitOrigin-RevId: 79913a12f0cad4baf948430315aabf53f03b6475 Change-Id: I0cc3341fd333a1df313167bab72dc5a759c4a048
This commit is contained in:
parent
092ed9793a
commit
518f17501e
22 changed files with 360 additions and 224 deletions
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 (...)
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -74,6 +74,7 @@ cc_test(
|
|||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":fixed_array",
|
||||
"//absl/base:config",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/hash:hash_testing",
|
||||
"//absl/memory",
|
||||
|
@ -153,6 +154,7 @@ cc_test(
|
|||
":counting_allocator",
|
||||
":inlined_vector",
|
||||
":test_instance_tracker",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/base:raw_logging_internal",
|
||||
|
|
|
@ -147,6 +147,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::fixed_array
|
||||
absl::config
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
absl::memory
|
||||
|
@ -221,6 +222,7 @@ absl_cc_test(
|
|||
absl::counting_allocator
|
||||
absl::inlined_vector
|
||||
absl::test_instance_tracker
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
|
|
|
@ -217,7 +217,7 @@ class FixedArray {
|
|||
// Returns a reference the ith element of the fixed array.
|
||||
// REQUIRES: 0 <= i < size()
|
||||
reference operator[](size_type i) {
|
||||
assert(i < size());
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ class FixedArray {
|
|||
// ith element of the fixed array.
|
||||
// REQUIRES: 0 <= i < size()
|
||||
const_reference operator[](size_type i) const {
|
||||
assert(i < size());
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
|
@ -252,20 +252,32 @@ class FixedArray {
|
|||
// FixedArray::front()
|
||||
//
|
||||
// Returns a reference to the first element of the fixed array.
|
||||
reference front() { return *begin(); }
|
||||
reference front() {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::front() to return a reference to the first element
|
||||
// of a fixed array of const values.
|
||||
const_reference front() const { return *begin(); }
|
||||
const_reference front() const {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
// FixedArray::back()
|
||||
//
|
||||
// Returns a reference to the last element of the fixed array.
|
||||
reference back() { return *(end() - 1); }
|
||||
reference back() {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::back() to return a reference to the last element
|
||||
// of a fixed array of const values.
|
||||
const_reference back() const { return *(end() - 1); }
|
||||
const_reference back() const {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
// FixedArray::begin()
|
||||
//
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/hash/hash_testing.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
|
@ -188,6 +189,21 @@ TEST(FixedArrayTest, AtThrows) {
|
|||
"failed bounds check");
|
||||
}
|
||||
|
||||
TEST(FixedArrayTest, Hardened) {
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
absl::FixedArray<int> a = {1, 2, 3};
|
||||
EXPECT_EQ(a[2], 3);
|
||||
EXPECT_DEATH_IF_SUPPORTED(a[3], "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(a[-1], "");
|
||||
|
||||
absl::FixedArray<int> empty(0);
|
||||
EXPECT_DEATH_IF_SUPPORTED(empty[0], "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(empty[-1], "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(empty.front(), "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(empty.back(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(FixedArrayRelationalsTest, EqualArrays) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
absl::FixedArray<int, 5> a1(i);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "absl/algorithm/algorithm.h"
|
||||
#include "absl/base/internal/throw_delegate.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/container/internal/inlined_vector.h"
|
||||
|
@ -307,16 +308,14 @@ class InlinedVector {
|
|||
//
|
||||
// Returns a `reference` to the `i`th element of the inlined vector.
|
||||
reference operator[](size_type i) {
|
||||
assert(i < size());
|
||||
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
// Overload of `InlinedVector::operator[](...)` that returns a
|
||||
// `const_reference` to the `i`th element of the inlined vector.
|
||||
const_reference operator[](size_type i) const {
|
||||
assert(i < size());
|
||||
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
|
@ -331,7 +330,6 @@ class InlinedVector {
|
|||
base_internal::ThrowStdOutOfRange(
|
||||
"`InlinedVector::at(size_type)` failed bounds check");
|
||||
}
|
||||
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
|
@ -345,7 +343,6 @@ class InlinedVector {
|
|||
base_internal::ThrowStdOutOfRange(
|
||||
"`InlinedVector::at(size_type) const` failed bounds check");
|
||||
}
|
||||
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
|
@ -353,16 +350,14 @@ class InlinedVector {
|
|||
//
|
||||
// Returns a `reference` to the first element of the inlined vector.
|
||||
reference front() {
|
||||
assert(!empty());
|
||||
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return at(0);
|
||||
}
|
||||
|
||||
// Overload of `InlinedVector::front()` that returns a `const_reference` to
|
||||
// the first element of the inlined vector.
|
||||
const_reference front() const {
|
||||
assert(!empty());
|
||||
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return at(0);
|
||||
}
|
||||
|
||||
|
@ -370,16 +365,14 @@ class InlinedVector {
|
|||
//
|
||||
// Returns a `reference` to the last element of the inlined vector.
|
||||
reference back() {
|
||||
assert(!empty());
|
||||
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return at(size() - 1);
|
||||
}
|
||||
|
||||
// Overload of `InlinedVector::back()` that returns a `const_reference` to the
|
||||
// last element of the inlined vector.
|
||||
const_reference back() const {
|
||||
assert(!empty());
|
||||
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return at(size() - 1);
|
||||
}
|
||||
|
||||
|
@ -573,8 +566,8 @@ class InlinedVector {
|
|||
// of `v` starting at `pos`, returning an `iterator` pointing to the first of
|
||||
// the newly inserted elements.
|
||||
iterator insert(const_iterator pos, size_type n, const_reference v) {
|
||||
assert(pos >= begin());
|
||||
assert(pos <= end());
|
||||
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||
ABSL_HARDENING_ASSERT(pos <= end());
|
||||
|
||||
if (ABSL_PREDICT_TRUE(n != 0)) {
|
||||
value_type dealias = v;
|
||||
|
@ -600,8 +593,8 @@ class InlinedVector {
|
|||
EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
|
||||
iterator insert(const_iterator pos, ForwardIterator first,
|
||||
ForwardIterator last) {
|
||||
assert(pos >= begin());
|
||||
assert(pos <= end());
|
||||
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||
ABSL_HARDENING_ASSERT(pos <= end());
|
||||
|
||||
if (ABSL_PREDICT_TRUE(first != last)) {
|
||||
return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
|
||||
|
@ -619,8 +612,8 @@ class InlinedVector {
|
|||
template <typename InputIterator,
|
||||
DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
|
||||
iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
|
||||
assert(pos >= begin());
|
||||
assert(pos <= end());
|
||||
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||
ABSL_HARDENING_ASSERT(pos <= end());
|
||||
|
||||
size_type index = std::distance(cbegin(), pos);
|
||||
for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
|
||||
|
@ -636,8 +629,8 @@ class InlinedVector {
|
|||
// `pos`, returning an `iterator` pointing to the newly emplaced element.
|
||||
template <typename... Args>
|
||||
iterator emplace(const_iterator pos, Args&&... args) {
|
||||
assert(pos >= begin());
|
||||
assert(pos <= end());
|
||||
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||
ABSL_HARDENING_ASSERT(pos <= end());
|
||||
|
||||
value_type dealias(std::forward<Args>(args)...);
|
||||
return storage_.Insert(pos,
|
||||
|
@ -670,7 +663,7 @@ class InlinedVector {
|
|||
//
|
||||
// Destroys the element at `back()`, reducing the size by `1`.
|
||||
void pop_back() noexcept {
|
||||
assert(!empty());
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
|
||||
AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
|
||||
storage_.SubtractSize(1);
|
||||
|
@ -683,8 +676,8 @@ class InlinedVector {
|
|||
//
|
||||
// NOTE: may return `end()`, which is not dereferencable.
|
||||
iterator erase(const_iterator pos) {
|
||||
assert(pos >= begin());
|
||||
assert(pos < end());
|
||||
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||
ABSL_HARDENING_ASSERT(pos < end());
|
||||
|
||||
return storage_.Erase(pos, pos + 1);
|
||||
}
|
||||
|
@ -695,9 +688,9 @@ class InlinedVector {
|
|||
//
|
||||
// NOTE: may return `end()`, which is not dereferencable.
|
||||
iterator erase(const_iterator from, const_iterator to) {
|
||||
assert(from >= begin());
|
||||
assert(from <= to);
|
||||
assert(to <= end());
|
||||
ABSL_HARDENING_ASSERT(from >= begin());
|
||||
ABSL_HARDENING_ASSERT(from <= to);
|
||||
ABSL_HARDENING_ASSERT(to <= end());
|
||||
|
||||
if (ABSL_PREDICT_TRUE(from != to)) {
|
||||
return storage_.Erase(from, to);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/container/internal/counting_allocator.h"
|
||||
#include "absl/container/internal/test_instance_tracker.h"
|
||||
#include "absl/hash/hash_testing.h"
|
||||
|
@ -247,6 +248,16 @@ TEST(IntVec, Erase) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(IntVec, Hardened) {
|
||||
IntVec v;
|
||||
Fill(&v, 10);
|
||||
EXPECT_EQ(v[9], 9);
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
EXPECT_DEATH_IF_SUPPORTED(v[10], "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(v[-1], "");
|
||||
#endif
|
||||
}
|
||||
|
||||
// At the end of this test loop, the elements between [erase_begin, erase_end)
|
||||
// should have reference counts == 0, and all others elements should have
|
||||
// reference counts == 1.
|
||||
|
|
|
@ -48,7 +48,7 @@ ABSL_RANDOM_RANDEN_COPTS = select({
|
|||
":cpu_darwin": ABSL_RANDOM_HWAES_X64_FLAGS,
|
||||
":cpu_x64_windows_msvc": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
|
||||
":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
|
||||
":cpu_haswell": ABSL_RANDOM_HWAES_X64_FLAGS,
|
||||
":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS,
|
||||
":cpu_ppc": ["-mcrypto"],
|
||||
|
||||
# Supported by default or unsupported.
|
||||
|
@ -65,7 +65,7 @@ def absl_random_randen_copts_init():
|
|||
# These configs have consistent flags to enable HWAES intsructions.
|
||||
cpu_configs = [
|
||||
"ppc",
|
||||
"haswell",
|
||||
"k8",
|
||||
"darwin_x86_64",
|
||||
"darwin",
|
||||
"x64_windows_msvc",
|
||||
|
|
|
@ -74,6 +74,59 @@ class MutexRelock {
|
|||
|
||||
} // namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Persistent state of the flag data.
|
||||
|
||||
class FlagImpl;
|
||||
|
||||
class FlagState : public flags_internal::FlagStateInterface {
|
||||
public:
|
||||
template <typename V>
|
||||
FlagState(FlagImpl* flag_impl, const V& v, bool modified,
|
||||
bool on_command_line, int64_t counter)
|
||||
: flag_impl_(flag_impl),
|
||||
value_(v),
|
||||
modified_(modified),
|
||||
on_command_line_(on_command_line),
|
||||
counter_(counter) {}
|
||||
|
||||
~FlagState() override {
|
||||
if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kHeapAllocated)
|
||||
return;
|
||||
flags_internal::Delete(flag_impl_->op_, value_.dynamic);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class FlagImpl;
|
||||
|
||||
// Restores the flag to the saved state.
|
||||
void Restore() const override {
|
||||
if (!flag_impl_->RestoreState(*this)) return;
|
||||
|
||||
ABSL_INTERNAL_LOG(
|
||||
INFO, absl::StrCat("Restore saved value of ", flag_impl_->Name(),
|
||||
" to: ", flag_impl_->CurrentValue()));
|
||||
}
|
||||
|
||||
// Flag and saved flag data.
|
||||
FlagImpl* flag_impl_;
|
||||
union SavedValue {
|
||||
explicit SavedValue(void* v) : dynamic(v) {}
|
||||
explicit SavedValue(int64_t v) : one_word(v) {}
|
||||
explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {}
|
||||
|
||||
void* dynamic;
|
||||
int64_t one_word;
|
||||
flags_internal::AlignedTwoWords two_words;
|
||||
} value_;
|
||||
bool modified_;
|
||||
bool on_command_line_;
|
||||
int64_t counter_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Flag implementation, which does not depend on flag value type.
|
||||
|
||||
void FlagImpl::Init() {
|
||||
new (&data_guard_) absl::Mutex;
|
||||
|
||||
|
@ -86,13 +139,13 @@ void FlagImpl::Init() {
|
|||
break;
|
||||
case FlagValueStorageKind::kOneWordAtomic: {
|
||||
int64_t atomic_value;
|
||||
std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
|
||||
std::memcpy(&atomic_value, init_value.get(), flags_internal::Sizeof(op_));
|
||||
value_.one_word_atomic.store(atomic_value, std::memory_order_release);
|
||||
break;
|
||||
}
|
||||
case FlagValueStorageKind::kTwoWordsAtomic: {
|
||||
AlignedTwoWords atomic_value{0, 0};
|
||||
std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
|
||||
std::memcpy(&atomic_value, init_value.get(), flags_internal::Sizeof(op_));
|
||||
value_.two_words_atomic.store(atomic_value, std::memory_order_release);
|
||||
break;
|
||||
}
|
||||
|
@ -145,17 +198,17 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
|
|||
void FlagImpl::StoreValue(const void* src) {
|
||||
switch (ValueStorageKind()) {
|
||||
case FlagValueStorageKind::kHeapAllocated:
|
||||
Copy(op_, src, value_.dynamic);
|
||||
flags_internal::Copy(op_, src, value_.dynamic);
|
||||
break;
|
||||
case FlagValueStorageKind::kOneWordAtomic: {
|
||||
int64_t one_word_val;
|
||||
std::memcpy(&one_word_val, src, Sizeof(op_));
|
||||
std::memcpy(&one_word_val, src, flags_internal::Sizeof(op_));
|
||||
value_.one_word_atomic.store(one_word_val, std::memory_order_release);
|
||||
break;
|
||||
}
|
||||
case FlagValueStorageKind::kTwoWordsAtomic: {
|
||||
AlignedTwoWords two_words_val{0, 0};
|
||||
std::memcpy(&two_words_val, src, Sizeof(op_));
|
||||
std::memcpy(&two_words_val, src, flags_internal::Sizeof(op_));
|
||||
value_.two_words_atomic.store(two_words_val, std::memory_order_release);
|
||||
break;
|
||||
}
|
||||
|
@ -172,11 +225,17 @@ std::string FlagImpl::Filename() const {
|
|||
return flags_internal::GetUsageConfig().normalize_filename(filename_);
|
||||
}
|
||||
|
||||
absl::string_view FlagImpl::Typename() const { return ""; }
|
||||
|
||||
std::string FlagImpl::Help() const {
|
||||
return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
|
||||
: help_.gen_func();
|
||||
}
|
||||
|
||||
FlagStaticTypeId FlagImpl::TypeId() const {
|
||||
return flags_internal::StaticTypeId(op_);
|
||||
}
|
||||
|
||||
bool FlagImpl::IsModified() const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
return modified_;
|
||||
|
@ -195,10 +254,10 @@ std::string FlagImpl::DefaultValue() const {
|
|||
}
|
||||
|
||||
std::string FlagImpl::CurrentValue() const {
|
||||
DataGuard(); // Make sure flag initialized
|
||||
auto* guard = DataGuard(); // Make sure flag initialized
|
||||
switch (ValueStorageKind()) {
|
||||
case FlagValueStorageKind::kHeapAllocated: {
|
||||
absl::MutexLock l(DataGuard());
|
||||
absl::MutexLock l(guard);
|
||||
return flags_internal::Unparse(op_, value_.dynamic);
|
||||
}
|
||||
case FlagValueStorageKind::kOneWordAtomic: {
|
||||
|
@ -250,23 +309,53 @@ void FlagImpl::InvokeCallback() const {
|
|||
cb();
|
||||
}
|
||||
|
||||
bool FlagImpl::RestoreState(const void* value, bool modified,
|
||||
bool on_command_line, int64_t counter) {
|
||||
{
|
||||
absl::MutexLock l(DataGuard());
|
||||
std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
if (counter_ == counter) return false;
|
||||
bool modified = modified_;
|
||||
bool on_command_line = on_command_line_;
|
||||
switch (ValueStorageKind()) {
|
||||
case FlagValueStorageKind::kHeapAllocated: {
|
||||
return absl::make_unique<FlagState>(
|
||||
this, flags_internal::Clone(op_, value_.dynamic), modified,
|
||||
on_command_line, counter_);
|
||||
}
|
||||
case FlagValueStorageKind::kOneWordAtomic: {
|
||||
return absl::make_unique<FlagState>(
|
||||
this, value_.one_word_atomic.load(std::memory_order_acquire),
|
||||
modified, on_command_line, counter_);
|
||||
}
|
||||
case FlagValueStorageKind::kTwoWordsAtomic: {
|
||||
return absl::make_unique<FlagState>(
|
||||
this, value_.two_words_atomic.load(std::memory_order_acquire),
|
||||
modified, on_command_line, counter_);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FlagImpl::RestoreState(const FlagState& flag_state) {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
if (flag_state.counter_ == counter_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Write(value);
|
||||
|
||||
{
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
modified_ = modified;
|
||||
on_command_line_ = on_command_line;
|
||||
switch (ValueStorageKind()) {
|
||||
case FlagValueStorageKind::kHeapAllocated:
|
||||
StoreValue(flag_state.value_.dynamic);
|
||||
break;
|
||||
case FlagValueStorageKind::kOneWordAtomic:
|
||||
StoreValue(&flag_state.value_.one_word);
|
||||
break;
|
||||
case FlagValueStorageKind::kTwoWordsAtomic:
|
||||
StoreValue(&flag_state.value_.two_words);
|
||||
break;
|
||||
}
|
||||
|
||||
modified_ = flag_state.modified_;
|
||||
on_command_line_ = flag_state.on_command_line_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -290,10 +379,10 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
|
|||
}
|
||||
|
||||
void FlagImpl::Read(void* dst) const {
|
||||
DataGuard(); // Make sure flag initialized
|
||||
auto* guard = DataGuard(); // Make sure flag initialized
|
||||
switch (ValueStorageKind()) {
|
||||
case FlagValueStorageKind::kHeapAllocated: {
|
||||
absl::MutexLock l(DataGuard());
|
||||
absl::MutexLock l(guard);
|
||||
|
||||
flags_internal::CopyConstruct(op_, value_.dynamic, dst);
|
||||
break;
|
||||
|
@ -301,13 +390,13 @@ void FlagImpl::Read(void* dst) const {
|
|||
case FlagValueStorageKind::kOneWordAtomic: {
|
||||
const auto one_word_val =
|
||||
value_.one_word_atomic.load(std::memory_order_acquire);
|
||||
std::memcpy(dst, &one_word_val, Sizeof(op_));
|
||||
std::memcpy(dst, &one_word_val, flags_internal::Sizeof(op_));
|
||||
break;
|
||||
}
|
||||
case FlagValueStorageKind::kTwoWordsAtomic: {
|
||||
const auto two_words_val =
|
||||
value_.two_words_atomic.load(std::memory_order_acquire);
|
||||
std::memcpy(dst, &two_words_val, Sizeof(op_));
|
||||
std::memcpy(dst, &two_words_val, flags_internal::Sizeof(op_));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,6 @@ namespace absl {
|
|||
ABSL_NAMESPACE_BEGIN
|
||||
namespace flags_internal {
|
||||
|
||||
template <typename T>
|
||||
class Flag;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Flag value type operations, eg., parsing, copying, etc. are provided
|
||||
// by function specific to that type with a signature matching FlagOpFn.
|
||||
|
@ -148,36 +145,6 @@ inline FlagStaticTypeId StaticTypeId(FlagOpFn op) {
|
|||
op(FlagOp::kStaticTypeId, nullptr, nullptr, nullptr));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Persistent state of the flag data.
|
||||
|
||||
template <typename T>
|
||||
class FlagState : public flags_internal::FlagStateInterface {
|
||||
public:
|
||||
FlagState(Flag<T>* flag, T&& cur, bool modified, bool on_command_line,
|
||||
int64_t counter)
|
||||
: flag_(flag),
|
||||
cur_value_(std::move(cur)),
|
||||
modified_(modified),
|
||||
on_command_line_(on_command_line),
|
||||
counter_(counter) {}
|
||||
|
||||
~FlagState() override = default;
|
||||
|
||||
private:
|
||||
friend class Flag<T>;
|
||||
|
||||
// Restores the flag to the saved state.
|
||||
void Restore() const override;
|
||||
|
||||
// Flag and saved flag data.
|
||||
Flag<T>* flag_;
|
||||
T cur_value_;
|
||||
bool modified_;
|
||||
bool on_command_line_;
|
||||
int64_t counter_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Flag help auxiliary structs.
|
||||
|
||||
|
@ -341,13 +308,15 @@ struct FlagCallback {
|
|||
struct DynValueDeleter {
|
||||
explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
|
||||
void operator()(void* ptr) const {
|
||||
if (op != nullptr) Delete(op, ptr);
|
||||
if (op != nullptr) flags_internal::Delete(op, ptr);
|
||||
}
|
||||
|
||||
FlagOpFn op;
|
||||
};
|
||||
|
||||
class FlagImpl {
|
||||
class FlagState;
|
||||
|
||||
class FlagImpl final : public flags_internal::CommandLineFlag {
|
||||
public:
|
||||
constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
|
||||
FlagHelpArg help, FlagValueStorageKind value_kind,
|
||||
|
@ -368,15 +337,7 @@ class FlagImpl {
|
|||
data_guard_{} {}
|
||||
|
||||
// Constant access methods
|
||||
absl::string_view Name() const;
|
||||
std::string Filename() const;
|
||||
std::string Help() const;
|
||||
bool IsModified() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
void Read(void* dst) const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
template <typename T, typename std::enable_if<FlagUseHeapStorage<T>::value,
|
||||
int>::type = 0>
|
||||
void Get(T* dst) const {
|
||||
|
@ -404,34 +365,12 @@ class FlagImpl {
|
|||
|
||||
// Mutating access methods
|
||||
void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
|
||||
ValueSource source, std::string* err)
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Interfaces to operate on callbacks.
|
||||
void SetCallback(const FlagCallbackFunc mutation_callback)
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
||||
|
||||
// Interfaces to save/restore mutable flag data
|
||||
template <typename T>
|
||||
std::unique_ptr<FlagStateInterface> SaveState(Flag<T>* flag) const
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard()) {
|
||||
T&& cur_value = flag->Get();
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
return absl::make_unique<FlagState<T>>(
|
||||
flag, std::move(cur_value), modified_, on_command_line_, counter_);
|
||||
}
|
||||
bool RestoreState(const void* value, bool modified, bool on_command_line,
|
||||
int64_t counter) ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Value validation interfaces.
|
||||
void CheckDefaultValueParsingRoundtrip() const
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
bool ValidateInputValue(absl::string_view value) const
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Used in read/write operations to validate source/target has correct type.
|
||||
// For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to
|
||||
// absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
|
||||
|
@ -441,6 +380,10 @@ class FlagImpl {
|
|||
void AssertValidType(FlagStaticTypeId type_id) const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class Flag;
|
||||
friend class FlagState;
|
||||
|
||||
// Ensures that `data_guard_` is initialized and returns it.
|
||||
absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_);
|
||||
// Returns heap allocated value of type T initialized with default value.
|
||||
|
@ -467,6 +410,37 @@ class FlagImpl {
|
|||
return static_cast<FlagDefaultKind>(def_kind_);
|
||||
}
|
||||
|
||||
// CommandLineFlag interface implementation
|
||||
absl::string_view Name() const override;
|
||||
std::string Filename() const override;
|
||||
absl::string_view Typename() const override;
|
||||
std::string Help() const override;
|
||||
FlagStaticTypeId TypeId() const override;
|
||||
bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
bool IsSpecifiedOnCommandLine() const override
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
bool ValidateInputValue(absl::string_view value) const override
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
void CheckDefaultValueParsingRoundtrip() const override
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Interfaces to save and restore flags to/from persistent state.
|
||||
// Returns current flag state or nullptr if flag does not support
|
||||
// saving and restoring a state.
|
||||
std::unique_ptr<FlagStateInterface> SaveState() override
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Restores the flag state to the supplied state object. If there is
|
||||
// nothing to restore returns false. Otherwise returns true.
|
||||
bool RestoreState(const FlagState& flag_state)
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
|
||||
ValueSource source, std::string* error) override
|
||||
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
||||
|
||||
// Immutable flag's state.
|
||||
|
||||
// Flags name passed to ABSL_FLAG as second arg.
|
||||
|
@ -536,7 +510,7 @@ class FlagImpl {
|
|||
// flag reflection handle interface.
|
||||
|
||||
template <typename T>
|
||||
class Flag final : public flags_internal::CommandLineFlag {
|
||||
class Flag {
|
||||
public:
|
||||
constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
|
||||
const FlagDfltGenFunc default_value_gen)
|
||||
|
@ -568,60 +542,24 @@ class Flag final : public flags_internal::CommandLineFlag {
|
|||
}
|
||||
|
||||
// CommandLineFlag interface
|
||||
absl::string_view Name() const override { return impl_.Name(); }
|
||||
std::string Filename() const override { return impl_.Filename(); }
|
||||
absl::string_view Typename() const override { return ""; }
|
||||
std::string Help() const override { return impl_.Help(); }
|
||||
bool IsModified() const override { return impl_.IsModified(); }
|
||||
bool IsSpecifiedOnCommandLine() const override {
|
||||
absl::string_view Name() const { return impl_.Name(); }
|
||||
std::string Filename() const { return impl_.Filename(); }
|
||||
absl::string_view Typename() const { return ""; }
|
||||
std::string Help() const { return impl_.Help(); }
|
||||
bool IsModified() const { return impl_.IsModified(); }
|
||||
bool IsSpecifiedOnCommandLine() const {
|
||||
return impl_.IsSpecifiedOnCommandLine();
|
||||
}
|
||||
std::string DefaultValue() const override { return impl_.DefaultValue(); }
|
||||
std::string CurrentValue() const override { return impl_.CurrentValue(); }
|
||||
bool ValidateInputValue(absl::string_view value) const override {
|
||||
return impl_.ValidateInputValue(value);
|
||||
}
|
||||
|
||||
// Interfaces to save and restore flags to/from persistent state.
|
||||
// Returns current flag state or nullptr if flag does not support
|
||||
// saving and restoring a state.
|
||||
std::unique_ptr<FlagStateInterface> SaveState() override {
|
||||
return impl_.SaveState(this);
|
||||
}
|
||||
|
||||
// Restores the flag state to the supplied state object. If there is
|
||||
// nothing to restore returns false. Otherwise returns true.
|
||||
bool RestoreState(const FlagState<T>& flag_state) {
|
||||
return impl_.RestoreState(&flag_state.cur_value_, flag_state.modified_,
|
||||
flag_state.on_command_line_, flag_state.counter_);
|
||||
}
|
||||
bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
|
||||
ValueSource source, std::string* error) override {
|
||||
return impl_.ParseFrom(value, set_mode, source, error);
|
||||
}
|
||||
void CheckDefaultValueParsingRoundtrip() const override {
|
||||
impl_.CheckDefaultValueParsingRoundtrip();
|
||||
}
|
||||
std::string DefaultValue() const { return impl_.DefaultValue(); }
|
||||
std::string CurrentValue() const { return impl_.CurrentValue(); }
|
||||
|
||||
private:
|
||||
friend class FlagState<T>;
|
||||
|
||||
void Read(void* dst) const override { impl_.Read(dst); }
|
||||
FlagStaticTypeId TypeId() const override { return &FlagStaticTypeIdGen<T>; }
|
||||
|
||||
template <typename U, bool do_register>
|
||||
friend class FlagRegistrar;
|
||||
// Flag's data
|
||||
FlagImpl impl_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void FlagState<T>::Restore() const {
|
||||
if (flag_->RestoreState(*this)) {
|
||||
ABSL_INTERNAL_LOG(INFO,
|
||||
absl::StrCat("Restore saved value of ", flag_->Name(),
|
||||
" to: ", flag_->CurrentValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// This class facilitates Flag object registration and tail expression-based
|
||||
// flag definition, for example:
|
||||
// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
|
||||
|
@ -629,7 +567,7 @@ template <typename T, bool do_register>
|
|||
class FlagRegistrar {
|
||||
public:
|
||||
explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
|
||||
if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
|
||||
if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_);
|
||||
}
|
||||
|
||||
FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && {
|
||||
|
|
|
@ -283,7 +283,7 @@ class string_view {
|
|||
// Returns the ith element of the `string_view` using the array operator.
|
||||
// Note that this operator does not perform any bounds checking.
|
||||
constexpr const_reference operator[](size_type i) const {
|
||||
return ABSL_ASSERT(i < size()), ptr_[i];
|
||||
return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
|
||||
}
|
||||
|
||||
// string_view::at()
|
||||
|
@ -303,14 +303,14 @@ class string_view {
|
|||
//
|
||||
// Returns the first element of a `string_view`.
|
||||
constexpr const_reference front() const {
|
||||
return ABSL_ASSERT(!empty()), ptr_[0];
|
||||
return ABSL_HARDENING_ASSERT(!empty()), ptr_[0];
|
||||
}
|
||||
|
||||
// string_view::back()
|
||||
//
|
||||
// Returns the last element of a `string_view`.
|
||||
constexpr const_reference back() const {
|
||||
return ABSL_ASSERT(!empty()), ptr_[size() - 1];
|
||||
return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1];
|
||||
}
|
||||
|
||||
// string_view::data()
|
||||
|
@ -329,7 +329,7 @@ class string_view {
|
|||
// Removes the first `n` characters from the `string_view`. Note that the
|
||||
// underlying string is not changed, only the view.
|
||||
void remove_prefix(size_type n) {
|
||||
assert(n <= length_);
|
||||
ABSL_HARDENING_ASSERT(n <= length_);
|
||||
ptr_ += n;
|
||||
length_ -= n;
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ class string_view {
|
|||
// Removes the last `n` characters from the `string_view`. Note that the
|
||||
// underlying string is not changed, only the view.
|
||||
void remove_suffix(size_type n) {
|
||||
assert(n <= length_);
|
||||
ABSL_HARDENING_ASSERT(n <= length_);
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ class string_view {
|
|||
(std::numeric_limits<difference_type>::max)();
|
||||
|
||||
static constexpr size_type CheckLengthInternal(size_type len) {
|
||||
return (void)ABSL_ASSERT(len <= kMaxSize), len;
|
||||
return ABSL_HARDENING_ASSERT(len <= kMaxSize), len;
|
||||
}
|
||||
|
||||
static constexpr size_type StrlenInternal(const char* str) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/dynamic_annotations.h"
|
||||
#include "absl/base/options.h"
|
||||
|
||||
#if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__)
|
||||
// We don't control the death messaging when using std::string_view.
|
||||
|
@ -820,7 +821,7 @@ TEST(StringViewTest, FrontBackSingleChar) {
|
|||
|
||||
TEST(StringViewTest, FrontBackEmpty) {
|
||||
#ifndef ABSL_USES_STD_STRING_VIEW
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
// Abseil's string_view implementation has debug assertions that check that
|
||||
// front() and back() are not called on an empty string_view.
|
||||
absl::string_view sv;
|
||||
|
@ -1130,7 +1131,7 @@ TEST(StringViewTest, Noexcept) {
|
|||
|
||||
TEST(StringViewTest, BoundsCheck) {
|
||||
#ifndef ABSL_USES_STD_STRING_VIEW
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
// Abseil's string_view implementation has bounds-checking in debug mode.
|
||||
absl::string_view h = "hello";
|
||||
ABSL_EXPECT_DEATH_IF_SUPPORTED(h[5], "");
|
||||
|
|
|
@ -1751,7 +1751,8 @@ static const intptr_t ignore_waiting_writers[] = {
|
|||
};
|
||||
|
||||
// Internal version of LockWhen(). See LockSlowWithDeadline()
|
||||
void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
|
||||
ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition *cond,
|
||||
int flags) {
|
||||
ABSL_RAW_CHECK(
|
||||
this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags),
|
||||
"condition untrue on return from LockSlow");
|
||||
|
@ -2017,7 +2018,7 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
|
|||
// which holds the lock but is not runnable because its condition is false
|
||||
// or it is in the process of blocking on a condition variable; it must requeue
|
||||
// itself on the mutex/condvar to wait for its condition to become true.
|
||||
void Mutex::UnlockSlow(SynchWaitParams *waitp) {
|
||||
ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
|
||||
intptr_t v = mu_.load(std::memory_order_relaxed);
|
||||
this->AssertReaderHeld();
|
||||
CheckForMutexCorruption(v, "Unlock");
|
||||
|
|
|
@ -412,11 +412,11 @@ class optional : private optional_internal::optional_data<T>,
|
|||
//
|
||||
// If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
|
||||
const T* operator->() const {
|
||||
assert(this->engaged_);
|
||||
ABSL_HARDENING_ASSERT(this->engaged_);
|
||||
return std::addressof(this->data_);
|
||||
}
|
||||
T* operator->() {
|
||||
assert(this->engaged_);
|
||||
ABSL_HARDENING_ASSERT(this->engaged_);
|
||||
return std::addressof(this->data_);
|
||||
}
|
||||
|
||||
|
@ -425,17 +425,17 @@ class optional : private optional_internal::optional_data<T>,
|
|||
// Accesses the underlying `T` value of an `optional`. If the `optional` is
|
||||
// empty, behavior is undefined.
|
||||
constexpr const T& operator*() const& {
|
||||
return ABSL_ASSERT(this->engaged_), reference();
|
||||
return ABSL_HARDENING_ASSERT(this->engaged_), reference();
|
||||
}
|
||||
T& operator*() & {
|
||||
assert(this->engaged_);
|
||||
ABSL_HARDENING_ASSERT(this->engaged_);
|
||||
return reference();
|
||||
}
|
||||
constexpr const T&& operator*() const && {
|
||||
return absl::move(reference());
|
||||
return ABSL_HARDENING_ASSERT(this->engaged_), absl::move(reference());
|
||||
}
|
||||
T&& operator*() && {
|
||||
assert(this->engaged_);
|
||||
ABSL_HARDENING_ASSERT(this->engaged_);
|
||||
return std::move(reference());
|
||||
}
|
||||
|
||||
|
|
|
@ -1057,8 +1057,7 @@ TEST(optionalTest, Value) {
|
|||
// test constexpr value()
|
||||
constexpr absl::optional<int> o1(1);
|
||||
static_assert(1 == o1.value(), ""); // const &
|
||||
#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
|
||||
!defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
|
||||
#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
|
||||
using COI = const absl::optional<int>;
|
||||
static_assert(2 == COI(2).value(), ""); // const &&
|
||||
#endif
|
||||
|
@ -1098,8 +1097,7 @@ TEST(optionalTest, DerefOperator) {
|
|||
|
||||
constexpr absl::optional<int> opt1(1);
|
||||
static_assert(*opt1 == 1, "");
|
||||
#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
|
||||
!defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
|
||||
#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
|
||||
using COI = const absl::optional<int>;
|
||||
static_assert(*COI(2) == 2, "");
|
||||
#endif
|
||||
|
|
|
@ -276,7 +276,7 @@ class Span {
|
|||
// Returns a reference to the i'th element of this span.
|
||||
constexpr reference operator[](size_type i) const noexcept {
|
||||
// MSVC 2015 accepts this as constexpr, but not ptr_[i]
|
||||
return ABSL_ASSERT(i < size()), *(data() + i);
|
||||
return ABSL_HARDENING_ASSERT(i < size()), *(data() + i);
|
||||
}
|
||||
|
||||
// Span::at()
|
||||
|
@ -295,7 +295,7 @@ class Span {
|
|||
// Returns a reference to the first element of this span. The span must not
|
||||
// be empty.
|
||||
constexpr reference front() const noexcept {
|
||||
return ABSL_ASSERT(size() > 0), *data();
|
||||
return ABSL_HARDENING_ASSERT(size() > 0), *data();
|
||||
}
|
||||
|
||||
// Span::back()
|
||||
|
@ -303,7 +303,7 @@ class Span {
|
|||
// Returns a reference to the last element of this span. The span must not
|
||||
// be empty.
|
||||
constexpr reference back() const noexcept {
|
||||
return ABSL_ASSERT(size() > 0), *(data() + size() - 1);
|
||||
return ABSL_HARDENING_ASSERT(size() > 0), *(data() + size() - 1);
|
||||
}
|
||||
|
||||
// Span::begin()
|
||||
|
@ -368,7 +368,7 @@ class Span {
|
|||
//
|
||||
// Removes the first `n` elements from the span.
|
||||
void remove_prefix(size_type n) noexcept {
|
||||
assert(size() >= n);
|
||||
ABSL_HARDENING_ASSERT(size() >= n);
|
||||
ptr_ += n;
|
||||
len_ -= n;
|
||||
}
|
||||
|
@ -377,7 +377,7 @@ class Span {
|
|||
//
|
||||
// Removes the last `n` elements from the span.
|
||||
void remove_suffix(size_type n) noexcept {
|
||||
assert(size() >= n);
|
||||
ABSL_HARDENING_ASSERT(size() >= n);
|
||||
len_ -= n;
|
||||
}
|
||||
|
||||
|
@ -665,7 +665,7 @@ constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
|
|||
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
Span<T> MakeSpan(T* begin, T* end) noexcept {
|
||||
return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
|
||||
return ABSL_HARDENING_ASSERT(begin <= end), Span<T>(begin, end - begin);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename C>
|
||||
|
@ -710,7 +710,7 @@ constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
|
|||
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
|
||||
return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin);
|
||||
return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename C>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/container/fixed_array.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "absl/hash/hash_testing.h"
|
||||
|
@ -233,7 +234,7 @@ TEST(IntSpan, ElementAccess) {
|
|||
EXPECT_EQ(s.front(), s[0]);
|
||||
EXPECT_EQ(s.back(), s[9]);
|
||||
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
EXPECT_DEATH_IF_SUPPORTED(s[-1], "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(s[10], "");
|
||||
#endif
|
||||
|
@ -273,6 +274,13 @@ TEST(IntSpan, RemovePrefixAndSuffix) {
|
|||
EXPECT_EQ(s.size(), 0);
|
||||
|
||||
EXPECT_EQ(v, MakeRamp(20, 1));
|
||||
|
||||
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
|
||||
absl::Span<int> prefix_death(v);
|
||||
EXPECT_DEATH_IF_SUPPORTED(prefix_death.remove_prefix(21), "");
|
||||
absl::Span<int> suffix_death(v);
|
||||
EXPECT_DEATH_IF_SUPPORTED(suffix_death.remove_suffix(21), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(IntSpan, Subspan) {
|
||||
|
|
|
@ -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");
|
||||
|
@ -18,11 +15,15 @@
|
|||
// Alternate options.h file, used in continuous integration testing to exercise
|
||||
// option settings not used by default.
|
||||
|
||||
#ifndef ABSL_BASE_OPTIONS_H_
|
||||
#define ABSL_BASE_OPTIONS_H_
|
||||
|
||||
#define ABSL_OPTION_USE_STD_ANY 0
|
||||
#define ABSL_OPTION_USE_STD_OPTIONAL 0
|
||||
#define ABSL_OPTION_USE_STD_STRING_VIEW 0
|
||||
#define ABSL_OPTION_USE_STD_VARIANT 0
|
||||
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
|
||||
#define ABSL_OPTION_INLINE_NAMESPACE_NAME ns
|
||||
#define ABSL_OPTION_HARDENED 1
|
||||
|
||||
#endif // ABSL_BASE_OPTIONS_H_
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
# Test scripts should source this file to get the identifiers.
|
||||
|
||||
readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
|
||||
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
|
||||
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200102"
|
||||
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200319"
|
||||
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200319"
|
||||
readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
|
||||
|
|
Loading…
Reference in a new issue