diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index f45b9a4..cbeb96c 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -20,8 +20,8 @@
   "base/internal/dynamic_annotations.h"
   "base/internal/endian.h"
   "base/internal/errno_saver.h"
-  "base/internal/hardening.h"
   "base/internal/hardening.cc"
+  "base/internal/hardening.h"
   "base/internal/hide_ptr.h"
   "base/internal/iterator_traits.h"
   "base/internal/low_level_alloc.cc"
@@ -31,19 +31,18 @@
   "base/internal/per_thread_tls.h"
   "base/internal/poison.cc"
   "base/internal/poison.h"
-  "base/prefetch.h"
   "base/internal/pretty_function.h"
   "base/internal/raw_logging.cc"
   "base/internal/raw_logging.h"
   "base/internal/scheduling_mode.h"
   "base/internal/scoped_set_env.cc"
   "base/internal/scoped_set_env.h"
-  "base/internal/strerror.h"
-  "base/internal/strerror.cc"
   "base/internal/spinlock.cc"
   "base/internal/spinlock.h"
   "base/internal/spinlock_wait.cc"
   "base/internal/spinlock_wait.h"
+  "base/internal/strerror.cc"
+  "base/internal/strerror.h"
   "base/internal/sysinfo.cc"
   "base/internal/sysinfo.h"
   "base/internal/thread_identity.cc"
@@ -64,18 +63,19 @@
   "base/options.h"
   "base/policy_checks.h"
   "base/port.h"
+  "base/prefetch.h"
   "base/thread_annotations.h"
-  "base/throw_delegate.h"
   "base/throw_delegate.cc"
+  "base/throw_delegate.h"
   "cleanup/cleanup.h"
   "cleanup/internal/cleanup.h"
   "container/btree_map.h"
   "container/btree_set.h"
   "container/chunked_queue.h"
-  "container/hash_container_defaults.h"
   "container/fixed_array.h"
   "container/flat_hash_map.h"
   "container/flat_hash_set.h"
+  "container/hash_container_defaults.h"
   "container/inlined_vector.h"
   "container/internal/btree.h"
   "container/internal/btree_container.h"
@@ -108,17 +108,16 @@
   "crc/crc32c.h"
   "crc/internal/cpu_detect.cc"
   "crc/internal/cpu_detect.h"
-  "crc/internal/crc32c.h"
-  "crc/internal/crc32c_inline.h"
-  "crc/internal/crc32_x86_arm_combined_simd.h"
   "crc/internal/crc.cc"
   "crc/internal/crc.h"
+  "crc/internal/crc32_x86_arm_combined_simd.h"
+  "crc/internal/crc32c.h"
+  "crc/internal/crc32c_inline.h"
   "crc/internal/crc_cord_state.cc"
   "crc/internal/crc_cord_state.h"
   "crc/internal/crc_internal.h"
-  "crc/internal/crc_x86_arm_combined.cc"
-  "crc/internal/crc_memcpy_fallback.cc"
   "crc/internal/crc_memcpy.h"
+  "crc/internal/crc_memcpy_fallback.cc"
   "crc/internal/crc_memcpy_x86_arm_combined.cc"
   "crc/internal/crc_non_temporal_memcpy.cc"
   "crc/internal/crc_x86_arm_combined.cc"
@@ -126,17 +125,10 @@
   "crc/internal/non_temporal_memcpy.h"
   "debugging/failure_signal_handler.cc"
   "debugging/failure_signal_handler.h"
-  "debugging/leak_check.h"
-  "debugging/stacktrace.cc"
-  "debugging/stacktrace.h"
-  "debugging/symbolize.cc"
-  "debugging/symbolize.h"
   "debugging/internal/address_is_readable.cc"
   "debugging/internal/address_is_readable.h"
   "debugging/internal/addresses.h"
   "debugging/internal/bounded_utf8_length_sequence.h"
-  "debugging/internal/borrowed_fixup_buffer.h"
-  "debugging/internal/borrowed_fixup_buffer.cc"
   "debugging/internal/decode_rust_punycode.cc"
   "debugging/internal/decode_rust_punycode.h"
   "debugging/internal/demangle.cc"
@@ -155,18 +147,23 @@
   "debugging/internal/utf8_for_code_point.h"
   "debugging/internal/vdso_support.cc"
   "debugging/internal/vdso_support.h"
+  "debugging/leak_check.h"
+  "debugging/stacktrace.cc"
+  "debugging/stacktrace.h"
+  "debugging/symbolize.cc"
+  "debugging/symbolize.h"
   "functional/any_invocable.h"
-  "functional/internal/front_binder.h"
   "functional/bind_front.h"
   "functional/function_ref.h"
   "functional/internal/any_invocable.h"
+  "functional/internal/front_binder.h"
   "functional/internal/function_ref.h"
   "functional/overload.h"
   "hash/hash.h"
-  "hash/internal/city.h"
   "hash/internal/city.cc"
-  "hash/internal/hash.h"
+  "hash/internal/city.h"
   "hash/internal/hash.cc"
+  "hash/internal/hash.h"
   "hash/internal/spy_hash_state.h"
   "hash/internal/weakly_mixed_integer.h"
   "log/absl_check.h"
@@ -177,6 +174,8 @@
   "log/die_if_null.h"
   "log/globals.cc"
   "log/globals.h"
+  "log/initialize.cc"
+  "log/initialize.h"
   "log/internal/append_truncated.h"
   "log/internal/check_impl.h"
   "log/internal/check_op.cc"
@@ -185,8 +184,8 @@
   "log/internal/conditions.h"
   "log/internal/config.h"
   "log/internal/container.h"
-  "log/internal/fnmatch.h"
   "log/internal/fnmatch.cc"
+  "log/internal/fnmatch.h"
   "log/internal/globals.cc"
   "log/internal/globals.h"
   "log/internal/log_format.cc"
@@ -199,8 +198,8 @@
   "log/internal/nullguard.cc"
   "log/internal/nullguard.h"
   "log/internal/nullstream.h"
-  "log/internal/proto.h"
   "log/internal/proto.cc"
+  "log/internal/proto.h"
   "log/internal/strip.h"
   "log/internal/structured.h"
   "log/internal/structured_proto.cc"
@@ -208,8 +207,6 @@
   "log/internal/vlog_config.cc"
   "log/internal/vlog_config.h"
   "log/internal/voidify.h"
-  "log/initialize.cc"
-  "log/initialize.h"
   "log/log.h"
   "log/log_entry.cc"
   "log/log_entry.h"
@@ -220,8 +217,8 @@
   "log/structured.h"
   "log/vlog_is_on.h"
   "memory/memory.h"
-  "meta/type_traits.h"
   "meta/internal/requires.h"
+  "meta/type_traits.h"
   "numeric/bits.h"
   "numeric/int128.cc"
   "numeric/int128.h"
@@ -246,15 +243,15 @@
   "random/gaussian_distribution.cc"
   "random/gaussian_distribution.h"
   "random/internal/distribution_caller.h"
-  "random/internal/fastmath.h"
+  "random/internal/entropy_pool.cc"
+  "random/internal/entropy_pool.h"
   "random/internal/fast_uniform_bits.h"
+  "random/internal/fastmath.h"
   "random/internal/generate_real.h"
   "random/internal/iostream_state_saver.h"
   "random/internal/nonsecure_base.h"
   "random/internal/pcg_engine.h"
   "random/internal/platform.h"
-  "random/internal/entropy_pool.cc"
-  "random/internal/entropy_pool.h"
   "random/internal/randen.cc"
   "random/internal/randen.h"
   "random/internal/randen_detect.cc"
@@ -283,15 +280,15 @@
   "random/uniform_int_distribution.h"
   "random/uniform_real_distribution.h"
   "random/zipf_distribution.h"
-  "status/internal/status_internal.h"
   "status/internal/status_internal.cc"
+  "status/internal/status_internal.h"
   "status/internal/statusor_internal.h"
-  "status/status.h"
   "status/status.cc"
-  "status/statusor.h"
-  "status/statusor.cc"
-  "status/status_payload_printer.h"
+  "status/status.h"
   "status/status_payload_printer.cc"
+  "status/status_payload_printer.h"
+  "status/statusor.cc"
+  "status/statusor.h"
   "strings/ascii.cc"
   "strings/ascii.h"
   "strings/charconv.cc"
@@ -304,6 +301,8 @@
   "strings/cord_buffer.h"
   "strings/escaping.cc"
   "strings/escaping.h"
+  "strings/has_absl_stringify.h"
+  "strings/has_ostream_operator.h"
   "strings/internal/append_and_overwrite.h"
   "strings/internal/charconv_bigint.cc"
   "strings/internal/charconv_bigint.h"
@@ -318,10 +317,10 @@
   "strings/internal/cord_rep_btree_navigator.h"
   "strings/internal/cord_rep_btree_reader.cc"
   "strings/internal/cord_rep_btree_reader.h"
+  "strings/internal/cord_rep_consume.cc"
+  "strings/internal/cord_rep_consume.h"
   "strings/internal/cord_rep_crc.cc"
   "strings/internal/cord_rep_crc.h"
-  "strings/internal/cord_rep_consume.h"
-  "strings/internal/cord_rep_consume.cc"
   "strings/internal/cord_rep_flat.h"
   "strings/internal/cordz_functions.cc"
   "strings/internal/cordz_functions.h"
@@ -334,34 +333,13 @@
   "strings/internal/cordz_statistics.h"
   "strings/internal/cordz_update_scope.h"
   "strings/internal/cordz_update_tracker.h"
-  "strings/internal/damerau_levenshtein_distance.h"
   "strings/internal/damerau_levenshtein_distance.cc"
+  "strings/internal/damerau_levenshtein_distance.h"
+  "strings/internal/escaping.cc"
+  "strings/internal/escaping.h"
   "strings/internal/generic_printer.cc"
   "strings/internal/generic_printer.h"
   "strings/internal/generic_printer_internal.h"
-  "strings/internal/stl_type_traits.h"
-  "strings/internal/string_constant.h"
-  "strings/internal/stringify_sink.h"
-  "strings/internal/stringify_sink.cc"
-  "strings/has_absl_stringify.h"
-  "strings/has_ostream_operator.h"
-  "strings/match.cc"
-  "strings/match.h"
-  "strings/numbers.cc"
-  "strings/numbers.h"
-  "strings/str_format.h"
-  "strings/str_cat.cc"
-  "strings/str_cat.h"
-  "strings/str_join.h"
-  "strings/str_replace.cc"
-  "strings/str_replace.h"
-  "strings/str_split.cc"
-  "strings/str_split.h"
-  "strings/strip.h"
-  "strings/substitute.cc"
-  "strings/substitute.h"
-  "strings/internal/escaping.h"
-  "strings/internal/escaping.cc"
   "strings/internal/memutil.cc"
   "strings/internal/memutil.h"
   "strings/internal/ostringstream.cc"
@@ -369,6 +347,7 @@
   "strings/internal/pow10_helper.cc"
   "strings/internal/pow10_helper.h"
   "strings/internal/resize_uninitialized.h"
+  "strings/internal/stl_type_traits.h"
   "strings/internal/str_format/arg.cc"
   "strings/internal/str_format/arg.h"
   "strings/internal/str_format/bind.cc"
@@ -385,40 +364,58 @@
   "strings/internal/str_format/parser.h"
   "strings/internal/str_join_internal.h"
   "strings/internal/str_split_internal.h"
+  "strings/internal/string_constant.h"
+  "strings/internal/stringify_sink.cc"
+  "strings/internal/stringify_sink.h"
   "strings/internal/utf8.cc"
   "strings/internal/utf8.h"
+  "strings/match.cc"
+  "strings/match.h"
+  "strings/numbers.cc"
+  "strings/numbers.h"
   "strings/resize_and_overwrite.h"
+  "strings/str_cat.cc"
+  "strings/str_cat.h"
+  "strings/str_format.h"
+  "strings/str_join.h"
+  "strings/str_replace.cc"
+  "strings/str_replace.h"
+  "strings/str_split.cc"
+  "strings/str_split.h"
+  "strings/strip.h"
+  "strings/substitute.cc"
+  "strings/substitute.h"
   "synchronization/barrier.cc"
   "synchronization/barrier.h"
   "synchronization/blocking_counter.cc"
   "synchronization/blocking_counter.h"
+  "synchronization/internal/create_thread_identity.cc"
+  "synchronization/internal/create_thread_identity.h"
+  "synchronization/internal/futex.h"
+  "synchronization/internal/futex_waiter.cc"
+  "synchronization/internal/futex_waiter.h"
+  "synchronization/internal/graphcycles.cc"
+  "synchronization/internal/graphcycles.h"
+  "synchronization/internal/kernel_timeout.cc"
+  "synchronization/internal/kernel_timeout.h"
+  "synchronization/internal/per_thread_sem.cc"
+  "synchronization/internal/per_thread_sem.h"
+  "synchronization/internal/pthread_waiter.cc"
+  "synchronization/internal/pthread_waiter.h"
+  "synchronization/internal/sem_waiter.cc"
+  "synchronization/internal/sem_waiter.h"
+  "synchronization/internal/stdcpp_waiter.cc"
+  "synchronization/internal/stdcpp_waiter.h"
+  "synchronization/internal/thread_pool.h"
+  "synchronization/internal/waiter.h"
+  "synchronization/internal/waiter_base.cc"
+  "synchronization/internal/waiter_base.h"
+  "synchronization/internal/win32_waiter.cc"
+  "synchronization/internal/win32_waiter.h"
   "synchronization/mutex.cc"
   "synchronization/mutex.h"
   "synchronization/notification.cc"
   "synchronization/notification.h"
-  "synchronization/internal/create_thread_identity.cc"
-  "synchronization/internal/create_thread_identity.h"
-  "synchronization/internal/futex.h"
-  "synchronization/internal/futex_waiter.h"
-  "synchronization/internal/futex_waiter.cc"
-  "synchronization/internal/graphcycles.cc"
-  "synchronization/internal/graphcycles.h"
-  "synchronization/internal/kernel_timeout.h"
-  "synchronization/internal/kernel_timeout.cc"
-  "synchronization/internal/per_thread_sem.cc"
-  "synchronization/internal/per_thread_sem.h"
-  "synchronization/internal/pthread_waiter.h"
-  "synchronization/internal/pthread_waiter.cc"
-  "synchronization/internal/sem_waiter.h"
-  "synchronization/internal/sem_waiter.cc"
-  "synchronization/internal/stdcpp_waiter.h"
-  "synchronization/internal/stdcpp_waiter.cc"
-  "synchronization/internal/thread_pool.h"
-  "synchronization/internal/waiter.h"
-  "synchronization/internal/waiter_base.h"
-  "synchronization/internal/waiter_base.cc"
-  "synchronization/internal/win32_waiter.h"
-  "synchronization/internal/win32_waiter.cc"
   "time/civil_time.cc"
   "time/civil_time.h"
   "time/clock.cc"
@@ -427,10 +424,6 @@
   "time/clock_interface.h"
   "time/duration.cc"
   "time/format.cc"
-  "time/simulated_clock.cc"
-  "time/simulated_clock.h"
-  "time/time.cc"
-  "time/time.h"
   "time/internal/cctz/include/cctz/civil_time.h"
   "time/internal/cctz/include/cctz/civil_time_detail.h"
   "time/internal/cctz/include/cctz/time_zone.h"
@@ -452,12 +445,16 @@
   "time/internal/cctz/src/time_zone_posix.h"
   "time/internal/cctz/src/tzfile.h"
   "time/internal/cctz/src/zone_info_source.cc"
+  "time/simulated_clock.cc"
+  "time/simulated_clock.h"
+  "time/time.cc"
+  "time/time.h"
   "types/any.h"
   "types/compare.h"
+  "types/internal/span.h"
   "types/optional.h"
   "types/optional_ref.h"
   "types/span.h"
-  "types/internal/span.h"
   "types/variant.h"
   "utility/utility.h"
   "debugging/leak_check.cc"
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index 2a25ac6..e33d648 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -60,3 +60,9 @@
     ],
     visibility = [":__subpackages__"],
 )
+
+# Expose internals to privileged external repositories.
+package_group(
+    name = "friends",
+    packages = [],
+)
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 6b39370..c6e4be6 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -56,6 +56,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [":config"],
 )
@@ -132,6 +133,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":atomic_hook",
@@ -155,6 +157,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/base:__pkg__",
     ],
     deps = [
@@ -185,6 +188,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":base_internal",
@@ -266,6 +270,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":config",
@@ -445,6 +450,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":config",
@@ -458,6 +464,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
 )
 
@@ -538,6 +545,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/base:__pkg__",
     ],
     deps = [
@@ -573,6 +581,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":base",
@@ -842,6 +851,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":config",
@@ -940,6 +950,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":config",
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index efcdc51..be10bb5 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -225,6 +225,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = ["//absl/types:compare"],
 )
@@ -441,7 +442,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
-        "//visibility:private",
+        "//absl:friends",
     ],
     deps = [
         ":common",
@@ -776,6 +777,9 @@
     copts = ABSL_TEST_COPTS,
     linkstatic = 1,
     tags = NOTEST_TAGS_MOBILE + [
+        "no_test_chromiumos_arm",
+        "no_test_chromiumos_armv7",
+        "no_test_chromiumos_x86_64",
         "no_test_loonix",
         # TODO(b/237097643): investigate race and remove
         "noarm_gemu",
@@ -939,6 +943,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -956,6 +961,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -972,6 +978,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -988,6 +995,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -1006,6 +1014,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -1021,6 +1030,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -1036,6 +1046,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -1052,6 +1063,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
@@ -1229,6 +1241,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
     ],
     deps = [
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 1adb396..5e9a483 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1582,7 +1582,7 @@
 // 2^sizeof(key_type) elements.
 template <size_t kSizeOfSizeT = sizeof(size_t)>
 constexpr size_t MaxValidSizeForKeySize(size_t key_size) {
-  if (key_size < kSizeOfSizeT) return uint64_t{1} << 8 * key_size;
+  if (key_size < kSizeOfSizeT) return size_t{1} << 8 * key_size;
   return (std::numeric_limits<size_t>::max)();
 }
 
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 610ba82..fd99b2c 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -96,6 +96,7 @@
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::Ge;
+using ::testing::HasSubstr;
 using ::testing::Lt;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
@@ -2734,16 +2735,11 @@
 
 // Invalid iterator use can trigger use-after-free in asan/hwasan,
 // use-of-uninitialized-value in msan, or invalidated iterator assertions.
-constexpr const char* kInvalidIteratorDeathMessage =
-    "use-after-free|use-of-uninitialized-value|invalidated "
-    "iterator|Invalid iterator|invalid iterator";
-
-// MSVC doesn't support | in regex.
-#if defined(_MSC_VER)
-constexpr bool kMsvc = true;
-#else
-constexpr bool kMsvc = false;
-#endif
+testing::Matcher<const std::string&> InvalidIteratorMatcher() {
+  return AnyOf(HasSubstr("invalidated iterator"), HasSubstr("Invalid iterator"),
+               HasSubstr("invalid iterator"), HasSubstr("use-after-free"),
+               HasSubstr("use-of-uninitialized-value"));
+}
 
 TYPED_TEST(SooTest, IteratorInvalidAssertsEqualityOperator) {
   if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
@@ -2785,7 +2781,6 @@
 TYPED_TEST(SooTest, IteratorInvalidAssertsEqualityOperatorRehash) {
   if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
     GTEST_SKIP() << "Assertions not enabled.";
-  if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regex.";
 #ifdef ABSL_HAVE_THREAD_SANITIZER
   GTEST_SKIP() << "ThreadSanitizer test runs fail on use-after-free even in "
                   "EXPECT_DEATH.";
@@ -2798,11 +2793,7 @@
   // Trigger a rehash in t.
   for (int i = 0; i < 10; ++i) t.insert(i);
 
-  const char* const kRehashedDeathMessage =
-      SwisstableGenerationsEnabled()
-          ? kInvalidIteratorDeathMessage
-          : "Invalid iterator comparison.*might have rehashed.*config=asan";
-  EXPECT_DEATH_IF_SUPPORTED(void(iter == t.begin()), kRehashedDeathMessage);
+  EXPECT_DEATH_IF_SUPPORTED(void(iter == t.begin()), InvalidIteratorMatcher());
 }
 
 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -3148,7 +3139,6 @@
 
 TEST(Iterator, InvalidUseCrashesWithSanitizers) {
   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
-  if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
 
   NonSooIntTable t;
   // Start with 1 element so that `it` is never an end iterator.
@@ -3156,15 +3146,13 @@
   for (int i = 0; i < 10; ++i) {
     auto it = t.begin();
     t.insert(i);
-    EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
-    EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
-                              kInvalidIteratorDeathMessage);
+    EXPECT_DEATH_IF_SUPPORTED(*it, InvalidIteratorMatcher());
+    EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()), InvalidIteratorMatcher());
   }
 }
 
 TEST(Iterator, InvalidUseWithReserveCrashesWithSanitizers) {
   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
-  if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
 
   IntTable t;
   t.reserve(10);
@@ -3185,9 +3173,8 @@
   // The first insert after reserved growth is 0 is guaranteed to rehash when
   // generations are enabled.
   t.insert(10);
-  EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
-  EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
-                            kInvalidIteratorDeathMessage);
+  EXPECT_DEATH_IF_SUPPORTED(*it, InvalidIteratorMatcher());
+  EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()), InvalidIteratorMatcher());
 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
   EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "heap-use-after-free");
 #endif
@@ -3195,7 +3182,6 @@
 
 TEST(Iterator, InvalidUseWithMoveCrashesWithSanitizers) {
   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
-  if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
 
   NonSooIntTable t1, t2;
   t1.insert(1);
@@ -3205,9 +3191,8 @@
   (void)ptr;
 
   t2 = std::move(t1);
-  EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
-  EXPECT_DEATH_IF_SUPPORTED(void(it == t2.begin()),
-                            kInvalidIteratorDeathMessage);
+  EXPECT_DEATH_IF_SUPPORTED(*it, InvalidIteratorMatcher());
+  EXPECT_DEATH_IF_SUPPORTED(void(it == t2.begin()), InvalidIteratorMatcher());
 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
   EXPECT_DEATH_IF_SUPPORTED(std::cout << **ptr, "heap-use-after-free");
 #endif
@@ -3462,7 +3447,6 @@
 
 TEST(Table, GenerationInfoResetsOnClear) {
   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
-  if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
 
   NonSooIntTable t;
   for (int i = 0; i < 1000; ++i) t.insert(i);
@@ -3473,7 +3457,7 @@
   t.insert(0);
   auto it = t.begin();
   t.insert(1);
-  EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
+  EXPECT_DEATH_IF_SUPPORTED(*it, InvalidIteratorMatcher());
 }
 
 TEST(Table, InvalidReferenceUseCrashesWithSanitizers) {
@@ -3883,7 +3867,6 @@
 #endif
 }
 
-// TODO(b/328794765): this check is very useful to run with ASAN in opt mode.
 TEST(Table, DestroyedCallsFail) {
 #ifdef NDEBUG
   ASSERT_EQ(SwisstableAssertAccessToDestroyedTable(),
@@ -3905,13 +3888,10 @@
   IntTable* t_ptr = &*t;
   EXPECT_TRUE(t_ptr->contains(1));
   t.reset();
-  std::string expected_death_message =
-#if defined(ABSL_HAVE_MEMORY_SANITIZER)
-      "use-of-uninitialized-value";
-#else
-      "destroyed hash table";
-#endif  // ABSL_HAVE_MEMORY_SANITIZER
-  EXPECT_DEATH_IF_SUPPORTED(t_ptr->contains(1), expected_death_message);
+  EXPECT_DEATH_IF_SUPPORTED(
+      t_ptr->contains(1),
+      AnyOf(HasSubstr("destroyed hash table"), HasSubstr("use-after-free"),
+            HasSubstr("use-of-uninitialized-value")));
 
 #endif  // ABSL_HAVE_THREAD_SANITIZER
 }
@@ -3923,6 +3903,10 @@
 #if !defined(__clang__) && defined(__GNUC__)
   GTEST_SKIP() << "Flaky on GCC.";
 #endif
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) && defined(NDEBUG)
+  // TODO(b/487002780): see if we can re-enable this test in opt-ASan mode.
+  GTEST_SKIP() << "Fails to die in opt ASAN.";
+#endif
   // When EXPECT_DEATH_IF_SUPPORTED is not executed, the code after it is not
   // executed as well.
   // We need to destruct the table correctly in such a case.
@@ -3943,13 +3927,9 @@
     do_lookup = true;
     t.reset();
   };
-  std::string expected_death_message =
-#ifdef NDEBUG
-      "destroyed hash table";
-#else
-      "Reentrant container access";
-#endif
-  EXPECT_DEATH_IF_SUPPORTED(destroy_with_lookup(), expected_death_message);
+  EXPECT_DEATH_IF_SUPPORTED(destroy_with_lookup(),
+                            AnyOf(HasSubstr("destroyed hash table"),
+                                  HasSubstr("Reentrant container access")));
 }
 
 TEST(Table, MovedFromCallsFail) {
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index aad5e28..a5c736c 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -36,33 +36,6 @@
 licenses(["notice"])
 
 cc_library(
-    name = "borrowed_fixup_buffer",
-    srcs = ["internal/borrowed_fixup_buffer.cc"],
-    hdrs = ["internal/borrowed_fixup_buffer.h"],
-    copts = ABSL_DEFAULT_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        "//absl/base:config",
-        "//absl/base:core_headers",
-        "//absl/base:malloc_internal",
-        "//absl/hash",
-    ],
-)
-
-cc_test(
-    name = "borrowed_fixup_buffer_test",
-    srcs = ["internal/borrowed_fixup_buffer_test.cc"],
-    copts = ABSL_TEST_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        ":borrowed_fixup_buffer",
-        "//absl/base:config",
-        "@googletest//:gtest",
-        "@googletest//:gtest_main",
-    ],
-)
-
-cc_library(
     name = "stacktrace",
     srcs = [
         "internal/stacktrace_aarch64-inl.inc",
@@ -81,7 +54,6 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        ":borrowed_fixup_buffer",
         ":debugging_internal",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -97,7 +69,6 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        ":borrowed_fixup_buffer",
         ":stacktrace",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -182,7 +153,10 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = ["//absl/log/internal:__pkg__"],
+    visibility = [
+        "//absl:friends",
+        "//absl/log/internal:__pkg__",
+    ],
     deps = [
         ":stacktrace",
         ":symbolize",
@@ -244,7 +218,7 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = ["//visibility:private"],
+    visibility = ["//absl:friends"],
     deps = [
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -261,6 +235,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/container:__pkg__",
         "//absl/debugging:__pkg__",
     ],
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index ab3a795..d8249fe 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -18,38 +18,6 @@
 
 absl_cc_library(
   NAME
-    borrowed_fixup_buffer
-  SRCS
-    "internal/borrowed_fixup_buffer.cc"
-  HDRS
-    "internal/borrowed_fixup_buffer.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  LINKOPTS
-    ${ABSL_DEFAULT_LINKOPTS}
-  DEPS
-    absl::config
-    absl::core_headers
-    absl::hash
-    absl::malloc_internal
-  PUBLIC
-)
-
-absl_cc_test(
-  NAME
-    borrowed_fixup_buffer_test
-  SRCS
-    "internal/borrowed_fixup_buffer_test.cc"
-  COPTS
-    ${ABSL_TEST_COPTS}
-  DEPS
-    absl::borrowed_fixup_buffer
-    absl::config
-    GTest::gmock_main
-)
-
-absl_cc_library(
-  NAME
     stacktrace
   HDRS
     "stacktrace.h"
@@ -70,7 +38,6 @@
   LINKOPTS
     $<$<BOOL:${EXECINFO_LIBRARY}>:${EXECINFO_LIBRARY}>
   DEPS
-    absl::borrowed_fixup_buffer
     absl::debugging_internal
     absl::config
     absl::core_headers
diff --git a/absl/debugging/internal/borrowed_fixup_buffer.cc b/absl/debugging/internal/borrowed_fixup_buffer.cc
deleted file mode 100644
index 507a0a2..0000000
--- a/absl/debugging/internal/borrowed_fixup_buffer.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2025 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/debugging/internal/borrowed_fixup_buffer.h"
-
-#include <assert.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <atomic>
-#include <iterator>
-#include <utility>
-
-#include "absl/base/attributes.h"
-#include "absl/base/config.h"
-#include "absl/base/internal/low_level_alloc.h"
-#include "absl/hash/hash.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace internal_stacktrace {
-
-// A buffer for holding fix-up information for stack traces of common sizes_.
-struct BorrowedFixupBuffer::FixupStackBuffer {
-  static constexpr size_t kMaxStackElements = 128;  // Can be reduced if needed
-  std::atomic_flag in_use{};
-  uintptr_t frames[kMaxStackElements];
-  int sizes[kMaxStackElements];
-
-  ABSL_CONST_INIT static FixupStackBuffer g_instances[kNumStaticBuffers];
-};
-
-ABSL_CONST_INIT BorrowedFixupBuffer::FixupStackBuffer
-    BorrowedFixupBuffer::FixupStackBuffer::g_instances[kNumStaticBuffers] = {};
-
-BorrowedFixupBuffer::~BorrowedFixupBuffer() {
-  if (borrowed_) {
-    std::move(*this).Unlock();
-  } else {
-    base_internal::LowLevelAlloc::Free(frames_);
-  }
-}
-
-BorrowedFixupBuffer::BorrowedFixupBuffer(size_t length)
-    : borrowed_(0 < length && length <= FixupStackBuffer::kMaxStackElements
-                    ? TryLock()
-                    : nullptr) {
-  if (borrowed_) {
-    InitViaBorrow();
-  } else {
-    InitViaAllocation(length);
-  }
-}
-
-void BorrowedFixupBuffer::InitViaBorrow() {
-  assert(borrowed_);
-  frames_ = borrowed_->frames;
-  sizes_ = borrowed_->sizes;
-}
-
-void BorrowedFixupBuffer::InitViaAllocation(size_t length) {
-  static_assert(alignof(decltype(*frames_)) >= alignof(decltype(*sizes_)),
-                "contiguous layout assumes decreasing alignment, otherwise "
-                "padding may be needed in the middle");
-  assert(!borrowed_);
-
-  base_internal::InitSigSafeArena();
-  void* buf = base_internal::LowLevelAlloc::AllocWithArena(
-      length * (sizeof(*frames_) + sizeof(*sizes_)),
-      base_internal::SigSafeArena());
-
-  if (buf == nullptr) {
-    frames_ = nullptr;
-    sizes_ = nullptr;
-    return;
-  }
-
-  frames_ = new (buf) uintptr_t[length];
-  sizes_ = new (static_cast<void*>(static_cast<unsigned char*>(buf) +
-                                   length * sizeof(*frames_))) int[length];
-}
-
-[[nodiscard]] BorrowedFixupBuffer::FixupStackBuffer*
-BorrowedFixupBuffer::TryLock() {
-  constexpr size_t kNumSlots = std::size(FixupStackBuffer::g_instances);
-  const size_t i = absl::Hash<const void*>()(this) % kNumSlots;
-  for (size_t k = 0; k < kNumSlots; ++k) {
-    auto* instance = &FixupStackBuffer::g_instances[(i + k) % kNumSlots];
-    // Use memory_order_acquire to ensure that no reads and writes on the
-    // borrowed buffer are reordered before the borrowing.
-    if (!instance->in_use.test_and_set(std::memory_order_acquire)) {
-      return instance;
-    }
-  }
-  return nullptr;
-}
-
-void BorrowedFixupBuffer::Unlock() && {
-  // Use memory_order_release to ensure that no reads and writes on the borrowed
-  // buffer are reordered after the borrowing.
-  borrowed_->in_use.clear(std::memory_order_release);
-}
-
-}  // namespace internal_stacktrace
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/debugging/internal/borrowed_fixup_buffer.h b/absl/debugging/internal/borrowed_fixup_buffer.h
deleted file mode 100644
index a8f00c8..0000000
--- a/absl/debugging/internal/borrowed_fixup_buffer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2025 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
-#define ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace internal_stacktrace {
-
-// An RAII type that temporarily acquires a buffer for stack trace fix-ups from
-// a pool of preallocated buffers, or attempts to allocate a new buffer if no
-// such buffer is available.
-// When destroyed, returns the buffer to the pool if it borrowed successfully,
-// otherwise deallocates any previously allocated buffer.
-class BorrowedFixupBuffer {
- public:
-  static constexpr size_t kNumStaticBuffers = 64;
-  ~BorrowedFixupBuffer();
-
-  // The number of frames to allocate space for. Note that allocations can fail.
-  explicit BorrowedFixupBuffer(size_t length);
-
-  uintptr_t* frames() const { return frames_; }
-  int* sizes() const { return sizes_; }
-
- private:
-  struct FixupStackBuffer;
-
-  uintptr_t* frames_;
-  int* sizes_;
-
-  // The borrowed pre-existing buffer, if any (if we haven't allocated our own)
-  FixupStackBuffer* const borrowed_;
-
-  void InitViaBorrow();
-  void InitViaAllocation(size_t length);
-
-  // Attempts to opportunistically borrow a small buffer in a thread- and
-  // signal-safe manner. Returns nullptr on failure.
-  [[nodiscard]] FixupStackBuffer* TryLock();
-
-  // Returns the borrowed buffer.
-  void Unlock() &&;
-
-  BorrowedFixupBuffer(const BorrowedFixupBuffer&) = delete;
-  BorrowedFixupBuffer& operator=(const BorrowedFixupBuffer&) = delete;
-};
-
-}  // namespace internal_stacktrace
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_DEBUGGING_INTERNAL_BORROWED_FIXUP_BUFFER_H_
diff --git a/absl/debugging/internal/borrowed_fixup_buffer_test.cc b/absl/debugging/internal/borrowed_fixup_buffer_test.cc
deleted file mode 100644
index a856c5d..0000000
--- a/absl/debugging/internal/borrowed_fixup_buffer_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2025 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/debugging/internal/borrowed_fixup_buffer.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <functional>
-#include <memory>
-
-#include "gtest/gtest.h"
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace internal_stacktrace {
-namespace {
-
-TEST(BorrowedFixupBuffer, ProperReuse) {
-  uintptr_t first_borrowed_frame = 0;
-  uintptr_t first_borrowed_size = 0;
-
-  // Ensure that we borrow the same buffer each time, indicating proper reuse.
-  // Disable loop unrolling. We need all iterations to match exactly, to coax
-  // reuse of the the same underlying buffer.
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC unroll 1  // <= 1 disables unrolling
-#endif
-  for (int i = 0; i < 100; ++i) {
-    BorrowedFixupBuffer buf0(0);
-    EXPECT_EQ(buf0.frames(), nullptr);
-    EXPECT_EQ(buf0.sizes(), nullptr);
-
-    BorrowedFixupBuffer buf1(1);
-    EXPECT_NE(buf1.frames(), nullptr);
-    EXPECT_NE(buf1.sizes(), nullptr);
-    if (first_borrowed_frame == 0) {
-      first_borrowed_frame = reinterpret_cast<uintptr_t>(buf1.frames());
-    } else {
-      EXPECT_EQ(reinterpret_cast<uintptr_t>(buf1.frames()),
-                first_borrowed_frame);
-    }
-    if (first_borrowed_size == 0) {
-      first_borrowed_size = reinterpret_cast<uintptr_t>(buf1.sizes());
-    } else {
-      EXPECT_EQ(reinterpret_cast<uintptr_t>(buf1.sizes()), first_borrowed_size);
-    }
-
-    BorrowedFixupBuffer buf2(2);
-    EXPECT_NE(buf2.frames(), buf1.frames());
-    EXPECT_NE(buf2.sizes(), buf1.sizes());
-    EXPECT_NE(buf2.frames(), nullptr);
-    EXPECT_NE(buf2.sizes(), nullptr);
-  }
-}
-
-TEST(BorrowedFixupBuffer, NoOverlap) {
-  using BufferPtr = std::unique_ptr<BorrowedFixupBuffer>;
-  static constexpr std::less<const void*> less;
-  static constexpr size_t kBufLen = 5;
-  static constexpr size_t kNumBuffers =
-      BorrowedFixupBuffer::kNumStaticBuffers * 37 + 1;
-
-  auto bufs = std::make_unique<BufferPtr[]>(kNumBuffers);
-  for (size_t i = 0; i < kNumBuffers; ++i) {
-    bufs[i] = std::make_unique<BorrowedFixupBuffer>(kBufLen);
-  }
-
-  std::sort(bufs.get(), bufs.get() + kNumBuffers,
-            [](const BufferPtr& a, const BufferPtr& b) {
-              return less(a->frames(), b->frames());
-            });
-
-  // Verify there are no overlaps
-  for (size_t i = 1; i < kNumBuffers; ++i) {
-    EXPECT_FALSE(less(bufs[i]->frames(), bufs[i - 1]->frames() + kBufLen));
-    EXPECT_FALSE(less(bufs[i]->sizes(), bufs[i - 1]->sizes() + kBufLen));
-  }
-}
-
-}  // namespace
-}  // namespace internal_stacktrace
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
index 1a770af..ad55eef 100644
--- a/absl/debugging/stacktrace.cc
+++ b/absl/debugging/stacktrace.cc
@@ -47,7 +47,6 @@
 #include "absl/base/config.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
-#include "absl/debugging/internal/borrowed_fixup_buffer.h"
 #include "absl/debugging/internal/stacktrace_config.h"
 
 #if defined(ABSL_STACKTRACE_INL_HEADER)
@@ -92,19 +91,6 @@
   }
 #endif
 
-  // Some implementations of FixUpStack may need to be passed frame
-  // information from Unwind, even if the caller doesn't need that
-  // information. We allocate the necessary buffers for such implementations
-  // here.
-  const internal_stacktrace::BorrowedFixupBuffer fixup_buffer(
-      unwind_with_fixup ? max_depth : 0);
-  if (frames == nullptr) {
-    frames = fixup_buffer.frames();
-  }
-  if (sizes == nullptr) {
-    sizes = fixup_buffer.sizes();
-  }
-
   Unwinder g = custom.load(std::memory_order_acquire);
   size_t size;
   // Add 1 to skip count for the unwinder function itself
@@ -117,14 +103,9 @@
       std::fill(frames, frames + size, uintptr_t());
     }
   } else {
-    size = static_cast<size_t>(
-        unwind_with_fixup
-            ? UnwindImpl<true, IS_WITH_CONTEXT>(
-                  result, frames, sizes, static_cast<int>(max_depth),
-                  skip_count, uc, min_dropped_frames)
-            : UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
-                  result, frames, sizes, static_cast<int>(max_depth),
-                  skip_count, uc, min_dropped_frames));
+    size = static_cast<size_t>(UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
+        result, frames, sizes, static_cast<int>(max_depth), skip_count, uc,
+        min_dropped_frames));
   }
   if (unwind_with_fixup) {
     internal_stacktrace::FixUpStack(result, frames, sizes, max_depth, size);
@@ -136,25 +117,14 @@
 
 }  // anonymous namespace
 
-ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
-internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames,
-                                    int* sizes, int max_depth, int skip_count) {
-  return Unwind<true, false>(result, frames, sizes,
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
+    void** result, int* sizes, int max_depth, int skip_count) {
+  return Unwind<true, false>(result, nullptr, sizes,
                              static_cast<size_t>(max_depth), skip_count,
                              nullptr, nullptr);
 }
 
 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
-internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames,
-                                               int* sizes, int max_depth,
-                                               int skip_count, const void* uc,
-                                               int* min_dropped_frames) {
-  return Unwind<true, true>(result, frames, sizes,
-                            static_cast<size_t>(max_depth), skip_count, uc,
-                            min_dropped_frames);
-}
-
-ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
 internal_stacktrace::GetStackTraceNoFixup(void** result, int max_depth,
                                           int skip_count) {
   return Unwind<false, false>(result, nullptr, nullptr,
@@ -162,6 +132,15 @@
                               nullptr, nullptr, /*unwind_with_fixup=*/false);
 }
 
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                          int skip_count, const void* uc,
+                          int* min_dropped_frames) {
+  return Unwind<true, true>(result, nullptr, sizes,
+                            static_cast<size_t>(max_depth), skip_count, uc,
+                            min_dropped_frames);
+}
+
 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
     void** result, int max_depth, int skip_count) {
   return Unwind<false, false>(result, nullptr, nullptr,
@@ -181,9 +160,8 @@
   custom.store(w, std::memory_order_release);
 }
 
-ABSL_ATTRIBUTE_ALWAYS_INLINE static inline int DefaultStackUnwinderImpl(
-    void** pcs, uintptr_t* frames, int* sizes, int depth, int skip,
-    const void* uc, int* min_dropped_frames) {
+int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
+                         const void* uc, int* min_dropped_frames) {
   skip++;  // For this function
   decltype(&UnwindImpl<false, false>) f;
   if (sizes == nullptr) {
@@ -199,25 +177,7 @@
       f = &UnwindImpl<true, true>;
     }
   }
-  return (*f)(pcs, frames, sizes, depth, skip, uc, min_dropped_frames);
-}
-
-ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
-internal_stacktrace::DefaultStackUnwinder(void** pcs, uintptr_t* frames,
-                                          int* sizes, int depth, int skip,
-                                          const void* uc,
-                                          int* min_dropped_frames) {
-  int n = DefaultStackUnwinderImpl(pcs, frames, sizes, depth, skip, uc,
-                                   min_dropped_frames);
-  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
-  return n;
-}
-
-ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder(
-    void** pcs, int* sizes, int depth, int skip, const void* uc,
-    int* min_dropped_frames) {
-  int n = DefaultStackUnwinderImpl(pcs, nullptr, sizes, depth, skip, uc,
-                                   min_dropped_frames);
+  int n = (*f)(pcs, nullptr, sizes, depth, skip, uc, min_dropped_frames);
   ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
   return n;
 }
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
index 79f7651..8e5002a 100644
--- a/absl/debugging/stacktrace.h
+++ b/absl/debugging/stacktrace.h
@@ -34,7 +34,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "absl/base/attributes.h"
 #include "absl/base/config.h"
 
 namespace absl {
@@ -42,43 +41,9 @@
 
 namespace internal_stacktrace {
 
-// Same as `absl::GetStackFrames`, but with an optional `frames` parameter to
-// allow callers to receive the raw stack frame addresses.
-// This is internal for now; use `absl::GetStackFrames()` instead.
-extern int GetStackFrames(void** result, uintptr_t* frames, int* sizes,
-                          int max_depth, int skip_count);
-
-// Same as `absl::GetStackFramesWithContext`, but with an optional `frames`
-// parameter to allow callers to receive a start address for each stack frame.
-// The address may be zero in cases where it cannot be computed.
-//
-// DO NOT use this function without consulting the owners of absl/debuggging.
-// There is NO GUARANTEE on the precise frame addresses returned on any given
-// platform. It is only intended to provide sufficient non-overlapping bounds on
-// the local variables of a stack frame when used in conjunction with the
-// returned frame sizes. The actual pointers may be ABI-dependent, may vary at
-// run time, and are subject to breakage without notice.
-//
-// Implementation note:
-// Currently, we *attempt* to return the Canonical Frame Address (CFA) in DWARF
-// on most platforms. This is the value of the stack pointer just before the
-// 'call' instruction is executed in the caller.
-// Not all platforms and toolchains support this exact address, so this should
-// not be relied on for correctness.
-extern int GetStackFramesWithContext(void** result, uintptr_t* frames,
-                                     int* sizes, int max_depth, int skip_count,
-                                     const void* uc, int* min_dropped_frames);
-
 // As above, but skips fix-ups for efficiency.
 extern int GetStackTraceNoFixup(void** result, int max_depth, int skip_count);
 
-// Same as `absl::DefaultStackUnwinder`, but with an optional `frames` parameter
-// to allow callers to receive the raw stack frame addresses.
-// This is internal for now; do not depend on this externally.
-extern int DefaultStackUnwinder(void** pcs, uintptr_t* frames, int* sizes,
-                                int max_depth, int skip_count, const void* uc,
-                                int* min_dropped_frames);
-
 }  // namespace internal_stacktrace
 
 // GetStackFrames()
@@ -123,13 +88,8 @@
 //
 // This routine may return fewer stack frame entries than are
 // available. Also note that `result` and `sizes` must both be non-null.
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFrames(void** result,
-                                                       int* sizes,
-                                                       int max_depth,
-                                                       int skip_count) {
-  return internal_stacktrace::GetStackFrames(result, nullptr, sizes, max_depth,
-                                             skip_count);
-}
+extern int GetStackFrames(void** result, int* sizes, int max_depth,
+                          int skip_count);
 
 // GetStackFramesWithContext()
 //
@@ -152,12 +112,9 @@
 // or other reasons. (This value will be set to `0` if no frames were dropped.)
 // The number of total stack frames is guaranteed to be >= skip_count +
 // max_depth + *min_dropped_frames.
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFramesWithContext(
-    void** result, int* sizes, int max_depth, int skip_count, const void* uc,
-    int* min_dropped_frames) {
-  return internal_stacktrace::GetStackFramesWithContext(
-      result, nullptr, sizes, max_depth, skip_count, uc, min_dropped_frames);
-}
+extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                                     int skip_count, const void* uc,
+                                     int* min_dropped_frames);
 
 // GetStackTrace()
 //
diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc
index 177db64..5b54fe0 100644
--- a/absl/debugging/stacktrace_test.cc
+++ b/absl/debugging/stacktrace_test.cc
@@ -17,7 +17,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <algorithm>
 #include <cerrno>
 #include <csignal>
 #include <cstring>
@@ -63,7 +62,6 @@
   static constexpr int kStackCount = 64;
   int depth;
   void* result[kStackCount];
-  uintptr_t frames[kStackCount];
   int sizes[kStackCount];
 };
 
@@ -193,48 +191,6 @@
       ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
   EXPECT_GT(g_should_fixup_calls, 0);
   EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
-
-  // ==========================================================================
-
-  g_fixup_calls = 0;
-  g_should_fixup_calls = 0;
-  a.depth = absl::internal_stacktrace::GetStackFrames(
-      a.result, a.frames, a.sizes, kStackCount, kSkip);
-  g_enable_fixup = !g_enable_fixup;
-  b.depth = absl::internal_stacktrace::GetStackFrames(
-      b.result, b.frames, b.sizes, kStackCount, kSkip);
-  EXPECT_THAT(
-      absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
-  EXPECT_THAT(
-      absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
-  EXPECT_THAT(
-      absl::MakeSpan(a.frames, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.frames, static_cast<size_t>(b.depth))));
-  EXPECT_GT(g_should_fixup_calls, 0);
-  EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
-
-  // ==========================================================================
-
-  g_fixup_calls = 0;
-  g_should_fixup_calls = 0;
-  a.depth = absl::internal_stacktrace::GetStackFramesWithContext(
-      a.result, a.frames, a.sizes, kStackCount, kSkip, nullptr, nullptr);
-  g_enable_fixup = !g_enable_fixup;
-  b.depth = absl::internal_stacktrace::GetStackFramesWithContext(
-      b.result, b.frames, b.sizes, kStackCount, kSkip, nullptr, nullptr);
-  EXPECT_THAT(
-      absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
-  EXPECT_THAT(
-      absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
-  EXPECT_THAT(
-      absl::MakeSpan(a.frames, static_cast<size_t>(a.depth)),
-      ContainerEq(absl::MakeSpan(b.frames, static_cast<size_t>(b.depth))));
-  EXPECT_GT(g_should_fixup_calls, 0);
-  EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
 }
 
 TEST(StackTrace, FixupNoFixupEquivalence) { FixupNoFixupEquivalenceNoInline(); }
@@ -351,86 +307,6 @@
   EXPECT_GT(g_fixup_calls, 0);
 }
 
-#if ABSL_HAVE_BUILTIN(__builtin_frame_address)
-struct FrameInfo {
-  const void* return_address;
-  uintptr_t frame_address;
-};
-
-// Returns the canonical frame address and return address for the current stack
-// frame, while capturing the stack trace at the same time.
-// This performs any platform-specific adjustments necessary to convert from the
-// compiler built-ins to the expected API outputs.
-ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS     // May read random elements from stack.
-    ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY  // May read random elements from stack.
-        ABSL_ATTRIBUTE_NOINLINE static FrameInfo
-        CaptureBacktraceNoInline(StackTrace& backtrace) {
-  FrameInfo result;
-  result.return_address = __builtin_return_address(0);
-  // Large enough to cover all realistic slots the return address could be in
-  const int kMaxReturnAddressIndex = 5;
-  void* const* bfa = static_cast<void* const*>(__builtin_frame_address(0));
-  backtrace.depth = absl::internal_stacktrace::GetStackFramesWithContext(
-      backtrace.result, backtrace.frames, backtrace.sizes,
-      StackTrace::kStackCount, /*skip_count=*/0,
-      /*uc=*/nullptr, /*min_dropped_frames=*/nullptr);
-  // Make sure the return address is at a reasonable location in the frame
-  ptrdiff_t i;
-  for (i = 0; i < kMaxReturnAddressIndex; ++i) {
-    // Avoid std::find() here, since it lacks no-sanitize attributes.
-    if (bfa[i] == result.return_address) {
-      break;
-    }
-  }
-  result.frame_address =
-      i < kMaxReturnAddressIndex
-          ? reinterpret_cast<uintptr_t>(
-                bfa + i + 1 /* get the Canonical Frame Address (CFA) */)
-          : 0;
-  return result;
-}
-
-TEST(StackTrace, CanonicalFrameAddresses) {
-  // Now capture a stack trace and verify that the return addresses and frame
-  // addresses line up for one frame.
-  StackTrace backtrace;
-  const auto [return_address, frame_address] =
-      CaptureBacktraceNoInline(backtrace);
-  auto return_addresses = absl::MakeSpan(backtrace.result)
-                              .subspan(0, static_cast<size_t>(backtrace.depth));
-  auto frame_addresses = absl::MakeSpan(backtrace.frames)
-                             .subspan(0, static_cast<size_t>(backtrace.depth));
-
-  // Many platforms don't support this by default.
-  bool support_is_expected = false;
-
-  if (support_is_expected) {
-    // If all zeros were returned, that is valid per the function's contract.
-    // It just means we don't support returning frame addresses on this
-    // platform.
-    bool supported = static_cast<size_t>(std::count(frame_addresses.begin(),
-                                                    frame_addresses.end(), 0)) <
-                     frame_addresses.size();
-    EXPECT_TRUE(supported);
-    if (supported) {
-      ASSERT_TRUE(frame_address)
-          << "unable to obtain frame address corresponding to return address";
-      EXPECT_THAT(return_addresses, Contains(return_address).Times(1));
-      EXPECT_THAT(frame_addresses, Contains(frame_address).Times(1));
-      ptrdiff_t ifound = std::find(return_addresses.begin(),
-                                   return_addresses.end(), return_address) -
-                         return_addresses.begin();
-      // Make sure we found the frame in the first place.
-      ASSERT_LT(ifound, backtrace.depth);
-      // Make sure the frame address actually corresponds to the return
-      // address.
-      EXPECT_EQ(frame_addresses[static_cast<size_t>(ifound)], frame_address);
-      // Make sure the addresses only appear once.
-    }
-  }
-}
-#endif
-
 // This test is Linux specific.
 #if defined(__linux__)
 const void* g_return_address = nullptr;
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 9835648..b5ecb7f 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -43,6 +43,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/flags:__pkg__",
     ],
     deps = [
@@ -62,6 +63,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/flags:__pkg__",
         "//absl/log:__pkg__",
     ],
@@ -129,7 +131,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
-        "//visibility:private",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
@@ -168,6 +170,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/flags:__pkg__",
         "//absl/flags/rust:__pkg__",
     ],
@@ -268,6 +271,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/flags:__pkg__",
     ],
     deps = [
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel
index 833a5f9..6635118 100644
--- a/absl/log/internal/BUILD.bazel
+++ b/absl/log/internal/BUILD.bazel
@@ -39,6 +39,9 @@
 
 package_group(
     name = "internal_users",
+    includes = [
+        "//absl:friends",
+    ],
     packages = [
         "//absl/log",
     ],
@@ -105,6 +108,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/log:__pkg__",
     ],
     deps = [
@@ -150,6 +154,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/log:__pkg__",
     ],
     deps = [
@@ -182,6 +187,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/log:__pkg__",
     ],
     deps = [
@@ -458,6 +464,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
         "//absl/log:__subpackages__",
     ],
     deps = [
@@ -555,6 +562,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc
index 52ab3d9..6c2350d 100644
--- a/absl/log/internal/log_message.cc
+++ b/absl/log/internal/log_message.cc
@@ -227,7 +227,8 @@
   EncodeVarint(EventTag::kSeverity,
                ProtoSeverity(entry.log_severity(), entry.verbosity()),
                &encoded_remaining());
-  EncodeVarint(EventTag::kThreadId, entry.tid(), &encoded_remaining());
+  EncodeVarint(EventTag::kThreadId, static_cast<uint64_t>(entry.tid()),
+               &encoded_remaining());
 }
 
 void LogMessage::LogMessageData::FinalizeEncodingAndFormat() {
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
index 3508135..f0f7aea 100644
--- a/absl/memory/memory.h
+++ b/absl/memory/memory.h
@@ -96,6 +96,53 @@
 // should use `std::make_unique`.
 using std::make_unique;
 
+namespace memory_internal {
+
+// Traits to select proper overload and return type for
+// `absl::make_unique_for_overwrite<>`.
+template <typename T>
+struct MakeUniqueResult {
+  using scalar = std::unique_ptr<T>;
+};
+template <typename T>
+struct MakeUniqueResult<T[]> {
+  using array = std::unique_ptr<T[]>;
+};
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+  using invalid = void;
+};
+
+}  // namespace memory_internal
+
+// These are make_unique_for_overwrite variants modeled after
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1973r1.pdf
+// Unlike absl::make_unique, values are default initialized rather than value
+// initialized.
+//
+// `absl::make_unique_for_overwrite` overload for non-array types.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::scalar
+    make_unique_for_overwrite() {
+  return std::unique_ptr<T>(new T);
+}
+
+// `absl::make_unique_for_overwrite` overload for an array T[] of unknown
+// bounds. The array allocation needs to use the `new T[size]` form and cannot
+// take element constructor arguments. The `std::unique_ptr` will manage
+// destructing these array elements.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::array
+    make_unique_for_overwrite(size_t n) {
+  return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]);
+}
+
+// `absl::make_unique_for_overwrite` overload for an array T[N] of known bounds.
+// This construction will be rejected.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::invalid
+    make_unique_for_overwrite(Args&&... /* args */) = delete;
+
 // -----------------------------------------------------------------------------
 // Function Template: RawPtr()
 // -----------------------------------------------------------------------------
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
index fafd3a4..aeb6001 100644
--- a/absl/memory/memory_test.cc
+++ b/absl/memory/memory_test.cc
@@ -64,6 +64,11 @@
   EXPECT_EQ(0, DestructorVerifier::instance_count());
 }
 
+TEST(MakeUniqueForOverwriteTest, Basic) {
+  std::unique_ptr<int> p = absl::make_unique_for_overwrite<int>();
+  p = absl::make_unique_for_overwrite<int>();
+}
+
 // InitializationVerifier fills in a pattern when allocated so we can
 // distinguish between its default and value initialized states (without
 // accessing truly uninitialized memory).
@@ -87,6 +92,28 @@
   int b;
 };
 
+TEST(Initialization, MakeUniqueForOverwrite) {
+  auto p = absl::make_unique_for_overwrite<InitializationVerifier>();
+
+  int pattern;
+  memset(&pattern, InitializationVerifier::kDefaultScalar, sizeof(pattern));
+
+  EXPECT_EQ(pattern, p->a);
+  EXPECT_EQ(pattern, p->b);
+}
+
+TEST(Initialization, MakeUniqueForOverwriteArray) {
+  auto p = absl::make_unique_for_overwrite<InitializationVerifier[]>(2);
+
+  int pattern;
+  memset(&pattern, InitializationVerifier::kDefaultArray, sizeof(pattern));
+
+  EXPECT_EQ(pattern, p[0].a);
+  EXPECT_EQ(pattern, p[0].b);
+  EXPECT_EQ(pattern, p[1].a);
+  EXPECT_EQ(pattern, p[1].b);
+}
+
 struct ArrayWatch {
   void* operator new[](size_t n) {
     allocs().push_back(n);
@@ -99,6 +126,17 @@
   }
 };
 
+TEST(MakeUniqueForOverwriteTest, Array) {
+  // Ensure state is clean before we start so that these tests
+  // are order-agnostic.
+  ArrayWatch::allocs().clear();
+
+  auto p = absl::make_unique_for_overwrite<ArrayWatch[]>(5);
+  static_assert(std::is_same<decltype(p), std::unique_ptr<ArrayWatch[]>>::value,
+                "unexpected return type");
+  EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
+}
+
 TEST(RawPtrTest, RawPointer) {
   int i = 5;
   EXPECT_EQ(&i, absl::RawPtr(&i));
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index 26468c6..6e52c6e 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -42,6 +42,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
@@ -67,6 +68,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel
index 00571b2..34e3d25 100644
--- a/absl/profiling/BUILD.bazel
+++ b/absl/profiling/BUILD.bazel
@@ -40,6 +40,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
@@ -77,6 +78,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         "//absl/base:config",
@@ -106,8 +108,8 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
-        # TODO(b/304670045): remove after periodic_sampler moves to //spanner/common.
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":exponential_biased",
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index d292d34..c2f2c36 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -29,6 +29,7 @@
 
 default_package_visibility = [
     "//absl/random:__pkg__",
+    "//absl:friends",
 ]
 
 package(
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 64e207b..5f42894 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -217,6 +217,7 @@
         "internal/escaping_test_common.h",
     ],
     copts = ABSL_TEST_COPTS,
+    tags = ["no_test_chromiumos_x86_64"],
     visibility = ["//visibility:private"],
     deps = [
         ":cord",
@@ -1557,6 +1558,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
         "//absl:__subpackages__",
+        "//absl:friends",
     ],
     deps = [
         ":str_format",
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index 6a75b1f..d6252d6 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -60,7 +60,6 @@
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/nullability.h"
-#include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/string_view.h"
 
@@ -131,7 +130,7 @@
 // ascii_isxdigit()
 //
 // Determines whether the given character can be represented as a hexadecimal
-// digit character (i.e. {0-9} or {A-F}).
+// digit character (i.e. {0-9} or {A-F} or {a-f}).
 inline bool ascii_isxdigit(unsigned char c) {
   return (ascii_internal::kPropertyBits[c] & 0x80) != 0;
 }
diff --git a/absl/strings/internal/append_and_overwrite.h b/absl/strings/internal/append_and_overwrite.h
index f8d62dc..7d4ce59 100644
--- a/absl/strings/internal/append_and_overwrite.h
+++ b/absl/strings/internal/append_and_overwrite.h
@@ -56,12 +56,10 @@
     // Make sure to always grow by at least a factor of 2x.
     const auto min_growth = str.capacity();
     if (ABSL_PREDICT_FALSE(str.capacity() > str.max_size() - min_growth)) {
-      resize = str.max_size();
+      str.reserve(str.max_size());
     } else if (resize < str.capacity() + min_growth) {
-      resize = str.capacity() + min_growth;
+      str.reserve(str.capacity() + min_growth);
     }
-  } else {
-    resize = str.capacity();
   }
 
   // Avoid calling StringResizeAndOverwrite() here since it does an MSAN
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
index 5c5f004..933e7a4 100644
--- a/absl/strings/internal/resize_uninitialized.h
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -80,18 +80,15 @@
 [[deprecated]]
 void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) {
   if (new_size > s->size()) {
-    size_t enlarged_new_size = new_size;
-    if (enlarged_new_size > s->capacity()) {
+    if (new_size > s->capacity()) {
       // Make sure to always grow by at least a factor of 2x. Change min_growth
       // if you want to experiment with other growth strategies.
       const auto min_growth = s->capacity();
       if (ABSL_PREDICT_FALSE(s->capacity() > s->max_size() - min_growth)) {
-        enlarged_new_size = s->max_size();
-      } else if (enlarged_new_size < s->capacity() + min_growth) {
-        enlarged_new_size = s->capacity() + min_growth;
+        s->reserve(s->max_size());
+      } else if (new_size < s->capacity() + min_growth) {
+        s->reserve(s->capacity() + min_growth);
       }
-    } else {
-      enlarged_new_size = s->capacity();
     }
     // This calls absl::strings_internal::StringResizeAndOverwriteImpl() because
     // the public API absl::StringResizeAndOverwrite() verifies that the
@@ -99,13 +96,12 @@
     // absl::strings_internal::StringResizeAndOverwriteImpl(). Instead it should
     // be implemented correctly with absl::StringResizeAndOverwrite().
     absl::strings_internal::StringResizeAndOverwriteImpl(
-        *s, enlarged_new_size,
-        [new_size](typename string_type::value_type*, size_t) {
+        *s, new_size, [](typename string_type::value_type*, size_t buf_size) {
           // TODO: b/446221957 - It is undefined behavior if any character in
           // the range [0, return_value) is uninitialized, but we rely on this
           // here to implement the old STLStringResizeUninitializedAmortized()
           // API.
-          return new_size;
+          return buf_size;
         });
   } else {
     s->erase(new_size);
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 5f9df0e..7698cfa 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -46,7 +46,6 @@
 #include "absl/base/internal/iterator_traits.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/ostringstream.h"
-#include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/resize_and_overwrite.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index 48eb6f9..1ada736 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -106,7 +106,6 @@
 #include "absl/base/port.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/has_absl_stringify.h"
-#include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/internal/stringify_sink.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/resize_and_overwrite.h"
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index b3b55e7..583eff2 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -65,6 +65,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
     ],
     deps = [
         "//absl/base",
@@ -295,6 +296,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
     ],
     deps = [
         ":synchronization",
@@ -343,6 +345,7 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = [
+        "//absl:friends",
     ],
     deps = [
         ":synchronization",
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index c31a3a0..4c8d2f9 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -41,7 +41,6 @@
 #include <ctime>
 #include <limits>
 #include <string>
-#include <vector>
 #if !HAS_STRPTIME
 #include <iomanip>
 #include <sstream>
@@ -215,19 +214,15 @@
 
 // Formats a std::tm using strftime(3).
 void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
-  // strftime(3) returns the number of characters placed in the output
-  // array (which may be 0 characters).  It also returns 0 to indicate
-  // an error, like the array wasn't large enough.  To accommodate this,
-  // the following code grows the buffer size from 2x the format string
-  // length up to 32x.
-  for (std::size_t i = 2; i != 32; i *= 2) {
-    std::size_t buf_size = fmt.size() * i;
-    std::vector<char> buf(buf_size);
-    if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
-      out->append(&buf[0], len);
-      return;
-    }
-  }
+  // We assume that 16 times the length of the format string will
+  // be sufficient to store the result.  The extreme case appears
+  // to be "%c" (2 chars), which, in the POSIX locale, produces
+  // "Thu Jan 1 00:00:00 1970" (24 chars).
+  auto out_size = out->size();
+  auto buf_size = (16 * fmt.size()) + 1;
+  out->resize(out_size + buf_size);
+  auto len = strftime(&(*out)[out_size], buf_size, fmt.c_str(), &tm);
+  out->resize(out_size + len);
 }
 
 // Used for %E#S/%E#f specifiers and for data values in parse().
@@ -335,12 +330,12 @@
 std::string format(const std::string& format, const time_point<seconds>& tp,
                    const detail::femtoseconds& fs, const time_zone& tz) {
   std::string result;
-  result.reserve(format.size());  // A reasonable guess for the result size.
+  result.reserve(2 * format.size());  // A guess for the result size.
   const time_zone::absolute_lookup al = tz.lookup(tp);
   const std::tm tm = ToTM(al);
 
   // Scratch buffer for internal conversions.
-  char buf[6 + (kDigits10_64 + 2)];  // enough for longest conversion %F
+  char buf[6 + (kDigits10_64 + 2)];  // enough for longest conversion (%F)
   char* const ep = buf + sizeof(buf);
   char* bp;  // works back from ep
 
@@ -349,23 +344,29 @@
   //   [pending ... cur) : formatting pending, but no special cases
   //   [cur ... format.end()) : unexamined
   // Initially, everything is in the unexamined part.
-  const char* pending = format.c_str();  // NUL terminated
+  const char* pending = format.data();
   const char* cur = pending;
-  const char* end = pending + format.length();
+  const char* const end = pending + format.size();
 
   while (cur != end) {  // while something is unexamined
     // Moves cur to the next percent sign.
     const char* start = cur;
-    while (cur != end && *cur != '%') ++cur;
+    while (cur != end && *cur != '%') {
+      if (*cur == '\0' && pending != start) {
+        FormatTM(&result, std::string(pending, cur), tm);
+        pending = start = cur;
+      }
+      ++cur;
+    }
 
     // If the new pending text is all ordinary, copy it out.
     if (cur != start && pending == start) {
-      result.append(pending, static_cast<std::size_t>(cur - pending));
+      result.append(pending, cur);
       pending = start = cur;
     }
 
     // Span the sequential percent signs.
-    const char* percent = cur;
+    const char* const percent = cur;
     while (cur != end && *cur == '%') ++cur;
 
     // If the new pending text is all percents, copy out one
@@ -384,26 +385,32 @@
     if (cur == end || (cur - percent) % 2 == 0) continue;
 
     // Simple specifiers that we handle ourselves.
-    if (strchr("YmdeFUuWwHMSTzZs%", *cur)) {
-      if (cur - 1 != pending) {
-        FormatTM(&result, std::string(pending, cur - 1), tm);
-      }
+    if (*cur == '\0' || strchr("YmdeFUuWwHMSTzZs%", *cur)) {
+      FormatTM(&result, std::string(pending, cur - 1), tm);
       switch (*cur) {
+        case '\0':
+          // Because we allow NULs in the format string, we must give
+          // some meaning to the "%\0" specifier.  We choose the common
+          // (but undefined) strftime() behavior of echoing unknown
+          // specifiers.
+          result.push_back('%');
+          result.push_back('\0');
+          break;
         case 'Y':
           // This avoids the tm.tm_year overflow problem for %Y, however
           // tm.tm_year will still be used by other specifiers like %D.
           bp = Format64(ep, 0, al.cs.year());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'm':
           bp = Format02d(ep, al.cs.month());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'd':
         case 'e':
           bp = Format02d(ep, al.cs.day());
           if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'F':
           bp = Format02d(ep, al.cs.day());
@@ -411,35 +418,35 @@
           bp = Format02d(bp, al.cs.month());
           *--bp = '-';
           bp = Format64(bp, 0, al.cs.year());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'U':
           bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'u':
           bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'W':
           bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'w':
           bp = Format64(ep, 0, tm.tm_wday);
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'H':
           bp = Format02d(ep, al.cs.hour());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'M':
           bp = Format02d(ep, al.cs.minute());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'S':
           bp = Format02d(ep, al.cs.second());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'T':
           bp = Format02d(ep, al.cs.second());
@@ -447,18 +454,18 @@
           bp = Format02d(bp, al.cs.minute());
           *--bp = ':';
           bp = Format02d(bp, al.cs.hour());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'z':
           bp = FormatOffset(ep, al.offset, "");
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case 'Z':
           result.append(al.abbr);
           break;
         case 's':
           bp = Format64(ep, 0, ToUnixSeconds(tp));
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           break;
         case '%':
           result.push_back('%');
@@ -472,33 +479,27 @@
     if (*cur == ':' && cur + 1 != end) {
       if (*(cur + 1) == 'z') {
         // Formats %:z.
-        if (cur - 1 != pending) {
-          FormatTM(&result, std::string(pending, cur - 1), tm);
-        }
+        FormatTM(&result, std::string(pending, cur - 1), tm);
         bp = FormatOffset(ep, al.offset, ":");
-        result.append(bp, static_cast<std::size_t>(ep - bp));
+        result.append(bp, ep);
         pending = cur += 2;
         continue;
       }
       if (*(cur + 1) == ':' && cur + 2 != end) {
         if (*(cur + 2) == 'z') {
           // Formats %::z.
-          if (cur - 1 != pending) {
-            FormatTM(&result, std::string(pending, cur - 1), tm);
-          }
+          FormatTM(&result, std::string(pending, cur - 1), tm);
           bp = FormatOffset(ep, al.offset, ":*");
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           pending = cur += 3;
           continue;
         }
         if (*(cur + 2) == ':' && cur + 3 != end) {
           if (*(cur + 3) == 'z') {
             // Formats %:::z.
-            if (cur - 1 != pending) {
-              FormatTM(&result, std::string(pending, cur - 1), tm);
-            }
+            FormatTM(&result, std::string(pending, cur - 1), tm);
             bp = FormatOffset(ep, al.offset, ":*:");
-            result.append(bp, static_cast<std::size_t>(ep - bp));
+            result.append(bp, ep);
             pending = cur += 4;
             continue;
           }
@@ -512,33 +513,25 @@
     // Format our extensions.
     if (*cur == 'T') {
       // Formats %ET.
-      if (cur - 2 != pending) {
-        FormatTM(&result, std::string(pending, cur - 2), tm);
-      }
+      FormatTM(&result, std::string(pending, cur - 2), tm);
       result.append("T");
       pending = ++cur;
     } else if (*cur == 'z') {
       // Formats %Ez.
-      if (cur - 2 != pending) {
-        FormatTM(&result, std::string(pending, cur - 2), tm);
-      }
+      FormatTM(&result, std::string(pending, cur - 2), tm);
       bp = FormatOffset(ep, al.offset, ":");
-      result.append(bp, static_cast<std::size_t>(ep - bp));
+      result.append(bp, ep);
       pending = ++cur;
     } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
       // Formats %E*z.
-      if (cur - 2 != pending) {
-        FormatTM(&result, std::string(pending, cur - 2), tm);
-      }
+      FormatTM(&result, std::string(pending, cur - 2), tm);
       bp = FormatOffset(ep, al.offset, ":*");
-      result.append(bp, static_cast<std::size_t>(ep - bp));
+      result.append(bp, ep);
       pending = cur += 2;
     } else if (*cur == '*' && cur + 1 != end &&
                (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
       // Formats %E*S or %E*F.
-      if (cur - 2 != pending) {
-        FormatTM(&result, std::string(pending, cur - 2), tm);
-      }
+      FormatTM(&result, std::string(pending, cur - 2), tm);
       char* cp = ep;
       bp = Format64(cp, 15, fs.count());
       while (cp != bp && cp[-1] == '0') --cp;
@@ -551,15 +544,13 @@
           if (cp == bp) *--bp = '0';
           break;
       }
-      result.append(bp, static_cast<std::size_t>(cp - bp));
+      result.append(bp, cp);
       pending = cur += 2;
     } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
       // Formats %E4Y.
-      if (cur - 2 != pending) {
-        FormatTM(&result, std::string(pending, cur - 2), tm);
-      }
+      FormatTM(&result, std::string(pending, cur - 2), tm);
       bp = Format64(ep, 4, al.cs.year());
-      result.append(bp, static_cast<std::size_t>(ep - bp));
+      result.append(bp, ep);
       pending = cur += 2;
     } else if (std::isdigit(*cur)) {
       // Possibly found %E#S or %E#f.
@@ -567,9 +558,7 @@
       if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
         if (*np == 'S' || *np == 'f') {
           // Formats %E#S or %E#f.
-          if (cur - 2 != pending) {
-            FormatTM(&result, std::string(pending, cur - 2), tm);
-          }
+          FormatTM(&result, std::string(pending, cur - 2), tm);
           bp = ep;
           if (n > 0) {
             if (n > kDigits10_64) n = kDigits10_64;
@@ -579,7 +568,7 @@
             if (*np == 'S') *--bp = '.';
           }
           if (*np == 'S') bp = Format02d(bp, al.cs.second());
-          result.append(bp, static_cast<std::size_t>(ep - bp));
+          result.append(bp, ep);
           pending = cur = ++np;
         }
       }
@@ -587,9 +576,7 @@
   }
 
   // Formats any remaining data.
-  if (end != pending) {
-    FormatTM(&result, std::string(pending, end), tm);
-  }
+  FormatTM(&result, std::string(pending, end), tm);
 
   return result;
 }
@@ -710,8 +697,12 @@
 bool parse(const std::string& format, const std::string& input,
            const time_zone& tz, time_point<seconds>* sec,
            detail::femtoseconds* fs, std::string* err) {
-  // The unparsed input.
+  // The unparsed input.  Even though we allow NULs in input, and
+  // match them against corresponding NULs in format, we depend on
+  // *edata being a NUL so that we can call strptime().  This also
+  // makes our handling of input easier.
   const char* data = input.c_str();  // NUL terminated
+  const char* const edata = data + input.size();
 
   // Skips leading whitespace.
   while (std::isspace(*data)) ++data;
@@ -737,7 +728,11 @@
   int offset = 0;  // No offset from passed tz.
   std::string zone = "UTC";
 
+  // Even though we allow NULs in format, and match them against
+  // corresponding NULs in input, we simplify its handling by also
+  // ensuring that *efmt is a NUL.
   const char* fmt = format.c_str();  // NUL terminated
+  const char* const efmt = fmt + format.size();
   bool twelve_hour = false;
   bool afternoon = false;
   int week_num = -1;
@@ -747,7 +742,7 @@
   std::int_fast64_t percent_s = 0;
 
   // Steps through format, one specifier at a time.
-  while (data != nullptr && *fmt != '\0') {
+  while (data != nullptr && fmt != efmt) {
     if (std::isspace(*fmt)) {
       while (std::isspace(*data)) ++data;
       while (std::isspace(*++fmt)) continue;
@@ -755,7 +750,7 @@
     }
 
     if (*fmt != '%') {
-      if (*data == *fmt) {
+      if (data != edata && *data == *fmt) {
         ++data;
         ++fmt;
       } else {
@@ -764,14 +759,21 @@
       continue;
     }
 
-    const char* percent = fmt;
-    if (*++fmt == '\0') {
+    const char* const percent = fmt;
+    if (++fmt == efmt) {
       data = nullptr;
       continue;
     }
     switch (*fmt++) {
+      case '\0':
+        // Because we allow NULs in the format string, we must give
+        // some meaning to the "%\0" specifier.  We choose the common
+        // (but undefined) strptime() behavior of failing on unknown
+        // specifiers.
+        data = nullptr;
+        continue;
       case 'Y':
-        // Symmetrically with FormatTime(), directly handing %Y avoids the
+        // Symmetrically with format(), directly handing %Y avoids the
         // tm.tm_year overflow problem.  However, tm.tm_year will still be
         // used by other specifiers like %D.
         data = ParseInt(data, 0, kyearmin, kyearmax, &year);
@@ -946,8 +948,8 @@
     }
 
     // Parses the current specifier.
-    const char* orig_data = data;
-    std::string spec(percent, static_cast<std::size_t>(fmt - percent));
+    const char* const orig_data = data;
+    std::string spec(percent, fmt);
     data = ParseTM(data, spec.c_str(), &tm);
 
     // If we successfully parsed %p we need to remember whether the result
@@ -956,10 +958,9 @@
     // to a PM hour.
     if (spec == "%p" && data != nullptr) {
       std::string test_input = "1";
-      test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
-      const char* test_data = test_input.c_str();
+      test_input.append(orig_data, data);
       std::tm tmp{};
-      ParseTM(test_data, "%I%p", &tmp);
+      ParseTM(test_input.c_str(), "%I%p", &tmp);
       afternoon = (tmp.tm_hour == 13);
     }
   }
@@ -978,7 +979,7 @@
   while (std::isspace(*data)) ++data;
 
   // parse() must consume the entire input string.
-  if (data != input.data() + input.size()) {
+  if (data != edata) {
     if (err != nullptr) *err = "Illegal trailing data in input string";
     return false;
   }
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 19dc973..f047d93 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -142,7 +142,7 @@
   time_zone tz = utc_time_zone();
   time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
 
-  // Starts with a couple basic edge cases.
+  // Start with basic edge cases.
   EXPECT_EQ("", absl::time_internal::cctz::format("", tp, tz));
   EXPECT_EQ(" ", absl::time_internal::cctz::format(" ", tp, tz));
   EXPECT_EQ("  ", absl::time_internal::cctz::format("  ", tp, tz));
@@ -786,6 +786,36 @@
             absl::time_internal::cctz::format("%Y-%W-%w", tp, utc));
 }
 
+TEST(Format, NULsInFormatString) {
+  time_zone tz = utc_time_zone();
+  time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+
+  // All NULs.
+  std::string nuls(32, '\0');
+  EXPECT_EQ(nuls, absl::time_internal::cctz::format(nuls, tp, tz));
+
+  // NULs amongst ordinary text plus the internal "%\0" specifier.
+  std::string percent_nul("\0X\0\0X%\0\0X\0\0X\0", 13);
+  EXPECT_EQ(percent_nul,
+            absl::time_internal::cctz::format(percent_nul, tp, tz));
+
+  // NULs amongst ordinary text plus a non-internal specifier (%I).
+  EXPECT_EQ(std::string("X\0\0\0X12\0X\0\0\0X", 13),
+            absl::time_internal::cctz::format(
+                std::string("X\0\0\0X%I\0X\0\0\0X", 13), tp, tz));
+
+#if defined(__linux__) && defined(__GLIBC__)
+  // Depending upon strftime() behavior on "%E"
+  // and "%O", "%E\0" and "%0\0" produce themselves.
+  std::string percent_E_nul("abc%E\0xyz", 9);
+  EXPECT_EQ(percent_E_nul,
+            absl::time_internal::cctz::format(percent_E_nul, tp, tz));
+  std::string percent_O_nul("abc%O\0xyz", 9);
+  EXPECT_EQ(percent_O_nul,
+            absl::time_internal::cctz::format(percent_O_nul, tp, tz));
+#endif
+}
+
 //
 // Testing parse()
 //
@@ -930,6 +960,9 @@
   const time_zone tz = utc_time_zone();
   auto tp = chrono::system_clock::from_time_t(0);
 
+  // No data.
+  EXPECT_FALSE(parse("X", "", tz, &tp));
+
   // Illegal trailing data.
   EXPECT_FALSE(parse("%S", "123", tz, &tp));
 
@@ -967,9 +1000,6 @@
   EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
   EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
   EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
-
-  // Check that we do not accept strings with embedded NULs.
-  EXPECT_FALSE(parse("%Y", std::string("2026\0payload", 12), tz, &tp));
 }
 
 TEST(Parse, PosixConversions) {
@@ -1581,6 +1611,41 @@
   EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
 }
 
+TEST(Parse, NULsInFormatAndInputStrings) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // Check that NULs are parsed just like any other chars.
+  EXPECT_FALSE(
+      parse(std::string("abc\0def", 7), std::string("abc\0xyz", 7), utc, &tp));
+  EXPECT_FALSE(
+      parse(std::string("%Y\0def", 6), std::string("2026\0xyz", 8), utc, &tp));
+  EXPECT_TRUE(
+      parse(std::string("%Y\0xyz", 6), std::string("2026\0xyz", 8), utc, &tp));
+  ExpectTime(tp, utc, 2026, 1, 1, 0, 0, 0, 0, false, "UTC");
+
+  // All NULs.
+  std::string nuls(32, '\0');
+  EXPECT_TRUE(parse(nuls, nuls, utc, &tp));
+  ExpectTime(tp, utc, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+
+  // The "%\0" specifier never matches, even on the empty string and itself.
+  std::string percent_nul("%\0", 2);
+  EXPECT_FALSE(parse(percent_nul, "", utc, &tp));
+  EXPECT_FALSE(parse(percent_nul, percent_nul, utc, &tp));
+
+#if defined(__linux__) && defined(__GLIBC__)
+  // Depending upon strptime() behavior on "%E"
+  // and "%O", "%E\0" and "%0\0" also never match.
+  std::string percent_E_nul("%E\0", 3);
+  EXPECT_FALSE(parse(percent_E_nul, "", utc, &tp));
+  EXPECT_FALSE(parse(percent_E_nul, percent_E_nul, utc, &tp));
+  std::string percent_O_nul("%O\0", 3);
+  EXPECT_FALSE(parse(percent_O_nul, "", utc, &tp));
+  EXPECT_FALSE(parse(percent_O_nul, percent_O_nul, utc, &tp));
+#endif
+}
+
 TEST(Parse, MaxRange) {
   const time_zone utc = utc_time_zone();
   time_point<absl::time_internal::cctz::seconds> tp;
@@ -1710,10 +1775,18 @@
   const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
   const auto subseconds = chrono::nanoseconds(654321);
 
+  // No format specifiers, but include NUL.
+  {
+    time_point<chrono::nanoseconds> out;
+    const auto fmt = std::string("\0\1\2\3\4\5\6\7abcdefgh01234567");
+    const auto s = absl::time_internal::cctz::format(fmt, in, lax);
+    EXPECT_TRUE(parse(fmt, s, lax, &out)) << s;
+  }
+
   // RFC3339, which renders subseconds.
   {
     time_point<chrono::nanoseconds> out;
-    const std::string s =
+    const auto s =
         absl::time_internal::cctz::format(RFC3339_full, in + subseconds, lax);
     EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
     EXPECT_EQ(in + subseconds, out);  // RFC3339_full includes %Ez
@@ -1722,8 +1795,7 @@
   // RFC1123, which only does whole seconds.
   {
     time_point<chrono::nanoseconds> out;
-    const std::string s =
-        absl::time_internal::cctz::format(RFC1123_full, in, lax);
+    const auto s = absl::time_internal::cctz::format(RFC1123_full, in, lax);
     EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
     EXPECT_EQ(in, out);  // RFC1123_full includes %z
   }
@@ -1741,7 +1813,7 @@
   {
     time_point<chrono::nanoseconds> out;
     time_zone utc = utc_time_zone();
-    const std::string s = absl::time_internal::cctz::format("%c", in, utc);
+    const auto s = absl::time_internal::cctz::format("%c", in, utc);
     EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
     EXPECT_EQ(in, out);
   }