about summary refs log tree commit diff
diff options
context:
space:
mode:
-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
-rw-r--r--absl/container/BUILD.bazel2
-rw-r--r--absl/container/CMakeLists.txt2
-rw-r--r--absl/container/fixed_array.h24
-rw-r--r--absl/container/fixed_array_test.cc16
-rw-r--r--absl/container/inlined_vector.h49
-rw-r--r--absl/container/inlined_vector_test.cc11
-rw-r--r--absl/copts/configure_copts.bzl4
-rw-r--r--absl/flags/internal/flag.cc131
-rw-r--r--absl/flags/internal/flag.h166
-rw-r--r--absl/strings/string_view.h12
-rw-r--r--absl/strings/string_view_test.cc5
-rw-r--r--absl/synchronization/mutex.cc5
-rw-r--r--absl/types/optional.h12
-rw-r--r--absl/types/optional_test.cc6
-rw-r--r--absl/types/span.h14
-rw-r--r--absl/types/span_test.cc10
-rw-r--r--ci/absl_alternate_options.h7
-rw-r--r--ci/linux_docker_containers.sh4
22 files changed, 358 insertions, 222 deletions
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 830d4729af3b..fd0c733e234b 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 24e2e9a6f820..89e93aad0bd0 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 547f93bafba9..2f6089f4c683 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 234137c7acb8..230bf1eecc4a 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_
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 709856414a0e..c7f7b0d9f4c0 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -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",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 99a8e9c0a5a1..a732fe8273ac 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -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
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index a9ce99bafd32..796dd629a6bf 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -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()
   //
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index c960fe51c100..9b1c224f8608 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -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);
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 2388d471dcc8..5f6f6154bf64 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -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);
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 5965eac77d03..415c60d9f1af 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -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.
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index 9dd6bd0ae4fe..ff9a5ea9f482 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -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",
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index a45e883e071c..56a5ed2bc468 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -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;
+}
 
-  Write(value);
+bool FlagImpl::RestoreState(const FlagState& flag_state) {
+  absl::MutexLock l(DataGuard());
 
-  {
-    absl::MutexLock l(DataGuard());
+  if (flag_state.counter_ == counter_) {
+    return false;
+  }
 
-    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;
     }
   }
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 2c4aba680a6e..f27e558b25a4 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -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.
@@ -149,36 +146,6 @@ inline FlagStaticTypeId StaticTypeId(FlagOpFn op) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// 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.
 
 // This is help argument for absl::Flag encapsulating the string literal pointer
@@ -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) && {
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index b314bc34b69c..8e348fcd69ce 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -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) {
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index 6ba0614437c6..ff31b51e87e8 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -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], "");
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 426558e6d275..6ee5f235ac93 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -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");
diff --git a/absl/types/optional.h b/absl/types/optional.h
index afda69a0b175..61540cfdb26a 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -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());
   }
 
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
index 47d5c8a29e00..874334e6c25b 100644
--- a/absl/types/optional_test.cc
+++ b/absl/types/optional_test.cc
@@ -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
diff --git a/absl/types/span.h b/absl/types/span.h
index 21cda34b1f22..734db695e3f3 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -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>
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index 6ac234d365ad..2584339bd309 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -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) {
diff --git a/ci/absl_alternate_options.h b/ci/absl_alternate_options.h
index f0c21fea9d6f..29b020d9fa65 100644
--- a/ci/absl_alternate_options.h
+++ b/ci/absl_alternate_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");
@@ -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_
diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh
index 2e81a6a717ca..cf056b3450ba 100644
--- a/ci/linux_docker_containers.sh
+++ b/ci/linux_docker_containers.sh
@@ -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"