diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 4944823..d490e65 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -293,6 +293,7 @@ "strings/cord_buffer.h" "strings/escaping.cc" "strings/escaping.h" + "strings/internal/append_and_overwrite.h" "strings/internal/charconv_bigint.cc" "strings/internal/charconv_bigint.h" "strings/internal/charconv_parse.cc"
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index dca7cba..73e4145 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc
@@ -62,7 +62,7 @@ int64_t UnscaledCycleClock::Now() { #ifdef __GLIBC__ - return __ppc_get_timebase(); + return static_cast<int64_t>(__ppc_get_timebase()); #else #ifdef __powerpc64__ int64_t tbr;
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc index f82ca8f..ade4edf 100644 --- a/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -223,8 +223,9 @@ } if (sizes != nullptr) { if (next_sp > sp) { - sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) - - absl::debugging_internal::StripPointerMetadata(sp); + sizes[n] = static_cast<int>( + absl::debugging_internal::StripPointerMetadata(next_sp) - + absl::debugging_internal::StripPointerMetadata(sp)); } else { // A frame-size of 0 is used to indicate unknown frame size. sizes[n] = 0;
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index bf6e5ab..27ee32a 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -245,6 +245,7 @@ } #endif + const size_t page_size = static_cast<size_t>(getpagesize()); const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp); const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp); @@ -273,8 +274,7 @@ // so we assume the large frame is legit if we know the real stack bounds // and are within the stack. if (new_fp_u <= old_fp_u || new_fp_u - old_fp_u > kMaxFrameBytes) { - if (stack_high < kUnknownStackEnd && - static_cast<size_t>(getpagesize()) < stack_low) { + if (stack_high < kUnknownStackEnd && page_size < stack_low) { // Stack bounds are known. if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) { // new_fp_u is not within the known stack. @@ -311,7 +311,12 @@ if (new_fp_u >= 0xffffe000) return nullptr; #endif #if !defined(_WIN32) - if (!STRICT_UNWINDING) { + const uintptr_t old_fp_page = old_fp_u & ~(page_size - 1); + const uintptr_t new_fp_page = new_fp_u & ~(page_size - 1); + if (old_fp_page == new_fp_page && (new_fp_u & (sizeof(void*) - 1)) == 0) { + // We dereferenced the old_fp above, so it is safe to dereference + // new_fp if it's on the same page as the old_fp and is aligned. + } else if (!STRICT_UNWINDING) { // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test // on AMD-based machines with VDSO-enabled kernels. // Make an extra sanity check to insure new_fp is readable.
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 67df814..420005c 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc
@@ -78,7 +78,8 @@ ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames, int* sizes, size_t max_depth, int skip_count, const void* uc, - int* min_dropped_frames) { + int* min_dropped_frames, + bool unwind_with_fixup = true) { static constexpr size_t kMinPageSize = 4096; // Allow up to ~half a page, leaving some slack space for local variables etc. @@ -100,7 +101,8 @@ bool must_free_frames = false; bool must_free_sizes = false; - bool unwind_with_fixup = internal_stacktrace::ShouldFixUpStack(); + unwind_with_fixup = + unwind_with_fixup && internal_stacktrace::ShouldFixUpStack(); #ifdef _WIN32 if (unwind_with_fixup) { @@ -194,6 +196,14 @@ 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, + static_cast<size_t>(max_depth), skip_count, + nullptr, nullptr, /*unwind_with_fixup=*/false); +} + 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,
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h index 8777172..79f7651 100644 --- a/absl/debugging/stacktrace.h +++ b/absl/debugging/stacktrace.h
@@ -69,6 +69,9 @@ 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.
diff --git a/absl/log/check_test_impl.inc b/absl/log/check_test_impl.inc index 495f85a..47af1dd 100644 --- a/absl/log/check_test_impl.inc +++ b/absl/log/check_test_impl.inc
@@ -255,6 +255,60 @@ ABSL_TEST_CHECK_LT(a, "b"); } +TEST(CHECKDeathTest, CheckWithCharStarAndStringPrintsTheCharStar) { + std::string str = "B"; + + // When the comparison happens as strings, then we print the CharT* as a + // string. + EXPECT_DEATH(ABSL_TEST_CHECK_EQ("A", str), + R"re(Check failed: \"A\" == str \(A vs. B\))re"); +} + +#if defined(GTEST_USES_SIMPLE_RE) && GTEST_USES_SIMPLE_RE +#define POINTER_VALUE_RE R"re(\w*)re" +#else +#define POINTER_VALUE_RE R"re((0x)*[0-9a-fA-F]*)re" +#endif + +#define POINTER_VS_POINTER_RE(lhs, rhs) "\\(" lhs " vs. " rhs "\\)" + +template <typename CharT> +void TestCharStarComparison() { + // When the comparison happens as pointers, we only print the pointer and not + // interpret it as a C-String because it might not be. + // Leave the CharTs uninitialized to trigger ASan/MSan failures if we actually + // read the pointers. + CharT* p1 = new CharT; + CharT* p2 = new CharT; + EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p1, p2), + R"re(Check failed: p1 == p2 )re" POINTER_VS_POINTER_RE( + POINTER_VALUE_RE, POINTER_VALUE_RE)); + CharT as_array[10]; + EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p1, as_array), + R"re(Check failed: p1 == as_array )re" POINTER_VS_POINTER_RE( + POINTER_VALUE_RE, POINTER_VALUE_RE)); + + const void* as_void = as_array; + EXPECT_DEATH(ABSL_TEST_CHECK_EQ(as_void, p2), + R"re(Check failed: as_void == p2 )re" POINTER_VS_POINTER_RE( + POINTER_VALUE_RE, POINTER_VALUE_RE)); + + delete p1; + delete p2; +} + +TEST(CHECKDeathTest, CheckWithCharStarStringification) { + TestCharStarComparison<char>(); + TestCharStarComparison<signed char>(); + TestCharStarComparison<unsigned char>(); + TestCharStarComparison<wchar_t>(); +#if defined(__cpp_char8_t) + TestCharStarComparison<char8_t>(); +#endif + TestCharStarComparison<char16_t>(); + TestCharStarComparison<char32_t>(); +} + // For testing using CHECK*() on anonymous enums. enum { CASE_A, CASE_B }; @@ -339,9 +393,11 @@ a = "xx"; EXPECT_DEATH(ABSL_TEST_CHECK_EQ(a, b), - "Check failed: a == b \\(xx vs. \\(null\\)\\)"); + R"re(Check failed: a == b )re" POINTER_VS_POINTER_RE( + POINTER_VALUE_RE, "\\(null\\)")); EXPECT_DEATH(ABSL_TEST_CHECK_EQ(b, a), - "Check failed: b == a \\(\\(null\\) vs. xx\\)"); + R"re(Check failed: b == a )re" POINTER_VS_POINTER_RE( + "\\(null\\)", POINTER_VALUE_RE)); std::nullptr_t n{}; EXPECT_DEATH(ABSL_TEST_CHECK_NE(n, nullptr),
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h index 532b37c..9bf908e 100644 --- a/absl/log/internal/check_op.h +++ b/absl/log/internal/check_op.h
@@ -393,10 +393,35 @@ std::conditional_t<std::is_signed_v<UnderlyingTypeT<T>>, int64_t, uint64_t>>> Detect(...); -} // namespace detect_specialization template <typename T> -using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); +using Detected = decltype(Detect<T>(0)); +} // namespace detect_specialization + +// If the comparison will happen as pointers, decay `char*` arguments to `void*` +// when printing them. There is no evidence that they are a NULL terminated +// C-String so printing them as such could lead to UB, and more importantly we +// compared pointers so showing the pointers is a better result. +template <typename T> +constexpr bool IsCharStarOrVoidStar() { + if constexpr (std::is_reference_v<T>) { + return IsCharStarOrVoidStar<std::remove_reference_t<T>>(); + } else if constexpr (std::is_array_v<T>) { + return IsCharStarOrVoidStar<std::decay_t<T>>(); + } else { + using U = std::remove_const_t<std::remove_pointer_t<T>>; + return std::is_pointer_v<T> && + (std::is_same_v<char, U> || std::is_same_v<unsigned char, U> || + std::is_same_v<signed char, U> || std::is_void_v<U>); + } +} + +template <typename T1, typename T2, + typename U1 = detect_specialization::Detected<T1>, + typename U2 = detect_specialization::Detected<T2>> +using CheckOpStreamType = + std::conditional_t<IsCharStarOrVoidStar<U1>() && IsCharStarOrVoidStar<U2>(), + const void*, U1>; // Build the error message string. Specify no inlining for code size. template <typename T1, typename T2> @@ -406,8 +431,8 @@ template <typename T1, typename T2> const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2, const char* absl_nonnull exprtext) { - if constexpr (std::is_same_v<CheckOpStreamType<T1>, UnprintableWrapper> && - std::is_same_v<CheckOpStreamType<T2>, UnprintableWrapper>) { + if constexpr (std::is_same_v<CheckOpStreamType<T1, T2>, UnprintableWrapper> && + std::is_same_v<CheckOpStreamType<T2, T1>, UnprintableWrapper>) { // No sense printing " (UNPRINTABLE vs. UNPRINTABLE)" return exprtext; } else { @@ -462,8 +487,8 @@ template <typename T1, typename T2> \ inline constexpr const char* absl_nullable name##Impl( \ const T1& v1, const T2& v2, const char* absl_nonnull exprtext) { \ - using U1 = CheckOpStreamType<T1>; \ - using U2 = CheckOpStreamType<T2>; \ + using U1 = CheckOpStreamType<T1, T2>; \ + using U2 = CheckOpStreamType<T2, T1>; \ return ABSL_PREDICT_TRUE(v1 op v2) \ ? nullptr \ : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 7537797..394222f 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel
@@ -192,3 +192,20 @@ "@googletest//:gtest_main", ], ) + +cc_test( + name = "status_matchers_with_unqualified_macros_test", + size = "small", + srcs = ["status_matchers_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + local_defines = ["ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS"], + deps = [ + ":status", + ":status_matchers", + ":statusor", + "//absl/strings", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +)
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index e140365..d0d134c 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt
@@ -141,3 +141,19 @@ absl::status_matchers GTest::gmock_main ) + +absl_cc_test( + NAME + status_matchers_with_unqualified_macros_test + SRCS + "status_matchers_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEFINES + "ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS" + DEPS + absl::status + absl::statusor + absl::status_matchers + GTest::gmock_main +)
diff --git a/absl/status/status_matchers.h b/absl/status/status_matchers.h index 837660e..6db7355 100644 --- a/absl/status/status_matchers.h +++ b/absl/status/status_matchers.h
@@ -20,6 +20,24 @@ // // Defines the following utilities: // +// ================= +// ABSL_EXPECT_OK(s) +// +// ABSL_ASSERT_OK(s) +// ================= +// Convenience macros for `EXPECT_THAT(s, IsOk())`, where `s` is either +// a `Status` or a `StatusOr<T>` or a `StatusProto`. +// +// There are no EXPECT_NOT_OK/ASSERT_NOT_OK macros since they would not +// provide much value (when they fail, they would just print the OK status +// which conveys no more information than `EXPECT_FALSE(s.ok())`. You can +// of course use `EXPECT_THAT(s, Not(IsOk()))` if you prefer _THAT style. +// +// If you want to check for particular errors, better alternatives are: +// EXPECT_THAT(s, StatusIs(expected_error)); +// EXPECT_THAT(s, StatusIs(_, _, HasSubstr("expected error"))); +// +// // =============== // `IsOkAndHolds(m)` // =============== @@ -76,6 +94,13 @@ namespace absl_testing { ABSL_NAMESPACE_BEGIN +// Macros for testing the results of functions that return absl::Status or +// absl::StatusOr<T> (for any type T). +#define ABSL_EXPECT_OK(expression) \ + EXPECT_THAT(expression, ::absl_testing::IsOk()) +#define ABSL_ASSERT_OK(expression) \ + ASSERT_THAT(expression, ::absl_testing::IsOk()) + // Returns a gMock matcher that matches a StatusOr<> whose status is // OK and whose value matches the inner matcher. template <typename InnerMatcherT> @@ -112,6 +137,29 @@ return status_internal::IsOkMatcher(); } +// By defining ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS, this library also +// provides unqualified versions of macros +// +// Unqualified macro names are likely to collide with those other projects, and +// so are not recommended. Further, this is true of any transitive dependency +// of Abseil; it is impossible to be confident no downstream library will not +// also define these macros itself nor depend on a different library that also +// defines them. +// +// To enable this, define `ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS` +// preferably at the command line, e.g. +// `-DABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS` or +// `local_defines = ["ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS"]` if using +// Bazel. +// +// These are turned on by default inside Google's internal codebase where their +// use is historically ubiquitous. Other OSS Google projects should use the +// qualified versions or the `EXPECT_THAT(..., IsOk())` form. +#ifdef ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS +#define EXPECT_OK(expression) ABSL_EXPECT_OK(expression) +#define ASSERT_OK(expression) ABSL_ASSERT_OK(expression) +#endif // ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS + ABSL_NAMESPACE_END } // namespace absl_testing
diff --git a/absl/status/status_matchers_test.cc b/absl/status/status_matchers_test.cc index 51a5f27..8656b2d 100644 --- a/absl/status/status_matchers_test.cc +++ b/absl/status/status_matchers_test.cc
@@ -39,6 +39,33 @@ using ::testing::Not; using ::testing::Ref; +TEST(StatusMatcherTest, AbslExpectAssertOk) { + ABSL_EXPECT_OK(absl::OkStatus()); + ABSL_ASSERT_OK(absl::OkStatus()); + EXPECT_NONFATAL_FAILURE(ABSL_EXPECT_OK(absl::InternalError("Smigla error")), + "Smigla error"); + EXPECT_FATAL_FAILURE(ABSL_ASSERT_OK(absl::InternalError("Smigla error")), + "Smigla error"); +} + +TEST(StatusMatcherTest, ExpectAssertOk) { +#ifdef ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS + EXPECT_OK(absl::OkStatus()); + ASSERT_OK(absl::OkStatus()); + EXPECT_NONFATAL_FAILURE(EXPECT_OK(absl::InternalError("Smigla error")), + "Smigla error"); + EXPECT_FATAL_FAILURE(ASSERT_OK(absl::InternalError("Smigla error")), + "Smigla error"); +#else +#ifdef EXPECT_OK + static_assert(false, "EXPECT_OK defined despite being turned off."); +#endif // EXPECT_OK +#ifdef ASSERT_OK + static_assert(false, "ASSERT_OK defined despite being turned off."); +#endif // ASSERT_OK +#endif // ABSL_DEFINE_UNQUALIFIED_STATUS_TESTING_MACROS +} + TEST(StatusMatcherTest, StatusIsOk) { EXPECT_THAT(absl::OkStatus(), IsOk()); } TEST(StatusMatcherTest, StatusOrIsOk) {
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 1ecc069..2e64f1a 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -100,6 +100,7 @@ "string_view.h", ], deps = [ + ":append_and_overwrite", ":charset", ":internal", ":resize_and_overwrite", @@ -135,6 +136,7 @@ copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":resize_and_overwrite", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", @@ -170,6 +172,32 @@ ], ) +cc_library( + name = "append_and_overwrite", + hdrs = ["internal/append_and_overwrite.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:private"], + deps = [ + ":resize_and_overwrite", + "//absl/base:config", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "append_and_overwrite_test", + srcs = ["internal/append_and_overwrite_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":append_and_overwrite", + "//absl/log:absl_check", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_test( name = "match_test", size = "small", @@ -625,6 +653,7 @@ copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":append_and_overwrite", ":cord_internal", ":cordz_info", ":cordz_update_scope",
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index da44ef7..24408ca 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -76,6 +76,7 @@ ${ABSL_DEFAULT_COPTS} DEPS absl::string_view + absl::strings_append_and_overwrite absl::strings_internal absl::strings_resize_and_overwrite absl::base @@ -139,6 +140,7 @@ absl::core_headers absl::endian absl::raw_logging_internal + absl::strings_resize_and_overwrite absl::type_traits ) @@ -170,6 +172,32 @@ GTest::gmock_main ) +absl_cc_library( + NAME + strings_append_and_overwrite + HDRS + "internal/append_and_overwrite.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + absl::strings_resize_and_overwrite +) + +absl_cc_test( + NAME + strings_append_and_overwrite_test + SRCS + "internal/append_and_overwrite_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_resize_and_overwrite + absl::absl_check + GTest::gmock_main +) + absl_cc_test( NAME match_test @@ -1030,6 +1058,7 @@ absl::raw_logging_internal absl::span absl::strings + absl::strings_append_and_overwrite absl::strings_resize_and_overwrite absl::type_traits absl::weakly_mixed_integer
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 91fcf91..d3014f3 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc
@@ -44,13 +44,13 @@ #include "absl/functional/function_ref.h" #include "absl/strings/cord_buffer.h" #include "absl/strings/escaping.h" +#include "absl/strings/internal/append_and_overwrite.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cordz_update_tracker.h" -#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/match.h" #include "absl/strings/resize_and_overwrite.h" #include "absl/strings/str_cat.h" @@ -1065,12 +1065,11 @@ } void AppendCordToString(const Cord& src, std::string* absl_nonnull dst) { - const size_t cur_dst_size = dst->size(); - const size_t new_dst_size = cur_dst_size + src.size(); - absl::strings_internal::STLStringResizeUninitializedAmortized(dst, - new_dst_size); - char* append_ptr = &(*dst)[cur_dst_size]; - src.CopyToArrayImpl(append_ptr); + strings_internal::StringAppendAndOverwrite( + *dst, src.size(), [&src](char* buf, size_t buf_size) { + src.CopyToArrayImpl(buf); + return buf_size; + }); } void Cord::CopyToArraySlowPath(char* absl_nonnull dst) const {
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index e551c66..49ce583 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc
@@ -28,6 +28,7 @@ #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/unaligned_access.h" +#include "absl/base/macros.h" #include "absl/base/nullability.h" #include "absl/strings/ascii.h" #include "absl/strings/charset.h" @@ -35,6 +36,7 @@ #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/utf8.h" #include "absl/strings/numbers.h" +#include "absl/strings/resize_and_overwrite.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -807,23 +809,18 @@ // 4 characters. Any leftover chars are added directly for good measure. const size_t dest_len = 3 * (slen / 4) + (slen % 4); - strings_internal::STLStringResizeUninitialized(dest, dest_len); - - // We are getting the destination buffer by getting the beginning of the - // string and converting it into a char *. - size_t len; - const bool ok = - Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len); - if (!ok) { - dest->clear(); - return false; - } - - // could be shorter if there was padding - assert(len <= dest_len); - dest->erase(len); - - return true; + bool ok; + StringResizeAndOverwrite( + *dest, dest_len, [src, slen, unbase64, &ok](char* buf, size_t buf_size) { + size_t len; + ok = Base64UnescapeInternal(src, slen, buf, buf_size, unbase64, &len); + if (!ok) { + len = 0; + } + assert(len <= buf_size); // Could be shorter if there was padding. + return len; + }); + return ok; } /* clang-format off */ @@ -878,15 +875,11 @@ } } -// This is a templated function so that T can be either a char* or a -// std::string. -template <typename T> -void BytesToHexStringInternal(const unsigned char* absl_nullable src, T dest, - size_t num) { - auto dest_ptr = &dest[0]; - for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) { +void BytesToHexStringInternal(const unsigned char* absl_nullable src, + char* dest, size_t num) { + for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest += 2) { const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2]; - std::copy(hex_p, hex_p + 2, dest_ptr); + std::copy(hex_p, hex_p + 2, dest); } } @@ -966,19 +959,23 @@ return false; } - absl::strings_internal::STLStringResizeUninitialized(&output, num_bytes); - auto hex_p = hex.cbegin(); - for (std::string::iterator bin_p = output.begin(); bin_p != output.end(); - ++bin_p) { - int h1 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)]; - int h2 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)]; - if (h1 == -1 || h2 == -1) { - output.resize(static_cast<size_t>(bin_p - output.begin())); - return false; - } - *bin_p = static_cast<char>((h1 << 4) + h2); - } + StringResizeAndOverwrite( + output, num_bytes, [hex](char* buf, size_t buf_size) { + auto hex_p = hex.cbegin(); + for (size_t i = 0; i < buf_size; ++i) { + int h1 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)]; + int h2 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)]; + if (h1 == -1 || h2 == -1) { + return size_t{0}; + } + buf[i] = static_cast<char>((h1 << 4) + h2); + } + return buf_size; + }); + if (output.size() != num_bytes) { + return false; + } *bytes = std::move(output); return true; } @@ -986,16 +983,22 @@ std::string HexStringToBytes(absl::string_view from) { std::string result; const auto num = from.size() / 2; - strings_internal::STLStringResizeUninitialized(&result, num); - absl::HexStringToBytesInternal<std::string&>(from.data(), result, num); + StringResizeAndOverwrite(result, num, [from](char* buf, size_t buf_size) { + absl::HexStringToBytesInternal<char*>(from.data(), buf, buf_size); + return buf_size; + }); return result; } std::string BytesToHexString(absl::string_view from) { std::string result; - strings_internal::STLStringResizeUninitialized(&result, 2 * from.size()); - absl::BytesToHexStringInternal<std::string&>( - reinterpret_cast<const unsigned char*>(from.data()), result, from.size()); + StringResizeAndOverwrite( + result, 2 * from.size(), [from](char* buf, size_t buf_size) { + absl::BytesToHexStringInternal( + reinterpret_cast<const unsigned char*>(from.data()), buf, + from.size()); + return buf_size; + }); return result; }
diff --git a/absl/strings/internal/append_and_overwrite.h b/absl/strings/internal/append_and_overwrite.h new file mode 100644 index 0000000..0bb1215 --- /dev/null +++ b/absl/strings/internal/append_and_overwrite.h
@@ -0,0 +1,85 @@ +// 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_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_ +#define ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_ + +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/base/optimization.h" +#include "absl/strings/resize_and_overwrite.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace strings_internal { + +// An internal-only variant similar to `absl::StringResizeAndOverwrite()` +// optimized for repeated appends to a string that uses exponential growth so +// that the amortized complexity of increasing the string size by a small amount +// is O(1), in contrast to O(str.size()) in the case of precise growth. Use of +// this function is subtle; see https://reviews.llvm.org/D102727 to understand +// the tradeoffs. +// +// Appends at most `append_n` characters to `str`, using the user-provided +// operation `append_op` to modify the possibly indeterminate +// contents. `append_op` must return the length of the buffer appended to `str`. +// +// Invalidates all iterators, pointers, and references into `str`, regardless +// of whether reallocation occurs. +// +// `append_op(value_type* buf, size_t buf_size)` is allowed to write +// `value_type{}` to `buf[buf_size]`, which facilitiates interoperation with +// functions that write a trailing NUL. +template <typename T, typename Op> +void StringAppendAndOverwrite(T& str, typename T::size_type append_n, + Op append_op) { + ABSL_HARDENING_ASSERT(str.size() <= str.max_size() - append_n); + auto old_size = str.size(); + auto resize = old_size + append_n; + + // Make sure to always grow by at least a factor of 2x. + if (resize > str.capacity()) { + if (ABSL_PREDICT_FALSE(str.capacity() > str.max_size() / 2)) { + resize = str.max_size(); + } else if (resize < str.capacity() * 2) { + resize = str.capacity() * 2; + } + } + + // Avoid calling StringResizeAndOverwrite() here since it does an MSAN + // verification on the entire string. StringResizeAndOverwriteImpl() is + // StringResizeAndOverwrite() without the MSAN verification. + StringResizeAndOverwriteImpl( + str, resize, + [old_size, append_n, do_append = std::move(append_op)]( + typename T::value_type* data_ptr, typename T::size_type) mutable { + auto num_appended = + std::move(do_append)(data_ptr + old_size, append_n); + ABSL_HARDENING_ASSERT(num_appended >= 0 && num_appended <= append_n); + return old_size + num_appended; + }); + +#if defined(ABSL_HAVE_MEMORY_SANITIZER) + // Only check the region appended to. Checking the entire string would cause + // pathological quadratic verfication on repeated small appends. + __msan_check_mem_is_initialized(str.data() + old_size, str.size() - old_size); +#endif +} + +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace absl + + +#endif // ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_
diff --git a/absl/strings/internal/append_and_overwrite_test.cc b/absl/strings/internal/append_and_overwrite_test.cc new file mode 100644 index 0000000..aa9c7a1 --- /dev/null +++ b/absl/strings/internal/append_and_overwrite_test.cc
@@ -0,0 +1,95 @@ +// 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/strings/internal/append_and_overwrite.h" + +#include <algorithm> +#include <cstddef> +#include <string> + +#include "gtest/gtest.h" +#include "absl/log/absl_check.h" + +namespace { + +struct AppendAndOverwriteParam { + size_t initial_size; + size_t append_capacity; + size_t append_size; +}; + +using StringAppendAndOverwriteTest = + ::testing::TestWithParam<AppendAndOverwriteParam>; + +TEST_P(StringAppendAndOverwriteTest, StringAppendAndOverwrite) { + const auto& param = GetParam(); + std::string s(param.initial_size, 'a'); + absl::strings_internal::StringAppendAndOverwrite( + s, param.append_capacity, [&](char* p, size_t n) { + ABSL_CHECK_EQ(n, param.append_capacity); + std::fill_n(p, param.append_size, 'b'); + p[param.append_size] = '\0'; + return param.append_size; + }); + + std::string expected = + std::string(param.initial_size, 'a') + + std::string(param.append_size, + 'b'); + + EXPECT_EQ(s, expected); + EXPECT_EQ(s.c_str()[s.size()], '\0'); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(StringAppendAndOverwriteTestSuite, + StringAppendAndOverwriteTest, + ::testing::ValuesIn<AppendAndOverwriteParam>({ + {0, 10, 5}, + {10, 10, 10}, + {10, 15, 15}, + {10, 20, 15}, + {10, 40, 40}, + {10, 50, 40}, + {30, 35, 35}, + {30, 45, 35}, + {10, 30, 15}, + })); +// clang-format on + +TEST(StringAppendAndOverwrite, AmortizedComplexity) { + std::string str; + std::string expected; + size_t prev_cap = str.capacity(); + int cap_increase_count = 0; + for (int i = 0; i < 1000; ++i) { + char c = static_cast<char>('a' + (i % 26)); + absl::strings_internal::StringAppendAndOverwrite( + str, 1, [c](char* buf, size_t buf_size) { + ABSL_CHECK_EQ(buf_size, 1); + buf[0] = c; + return size_t{1}; + }); + expected.push_back(c); + EXPECT_EQ(str, expected); + size_t new_cap = str.capacity(); + if (new_cap > prev_cap) { + ++cap_increase_count; + } + prev_cap = new_cap; + } + EXPECT_LT(cap_increase_count, 50); +} + +} // namespace
diff --git a/absl/strings/internal/escaping.h b/absl/strings/internal/escaping.h index 2186f77..b71fb7e 100644 --- a/absl/strings/internal/escaping.h +++ b/absl/strings/internal/escaping.h
@@ -17,7 +17,7 @@ #include <cassert> -#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/resize_and_overwrite.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -42,12 +42,14 @@ bool do_padding, const char* base64_chars) { const size_t calc_escaped_size = CalculateBase64EscapedLenInternal(szsrc, do_padding); - STLStringResizeUninitialized(dest, calc_escaped_size); - - const size_t escaped_len = Base64EscapeInternal( - src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding); - assert(calc_escaped_size == escaped_len); - dest->erase(escaped_len); + StringResizeAndOverwrite( + *dest, calc_escaped_size, + [src, szsrc, base64_chars, do_padding](char* buf, size_t buf_size) { + const size_t escaped_len = Base64EscapeInternal( + src, szsrc, buf, buf_size, base64_chars, do_padding); + assert(escaped_len == buf_size); + return escaped_len; + }); } } // namespace strings_internal
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index e4fa44e..ea0329c 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc
@@ -1059,6 +1059,17 @@ "0.000000000000000000000000000000000002" "25694915357879201529997415146671170141" "1837869002408041296803276054561138153076171875"); + + // Scientific exponent cases + // Round to even with all zeros after round digit + EXPECT_EQ(format("%0.13e", 1671075773261250), "1.6710757732612e+15"); + + // Rounding where precision is in first digit run + EXPECT_EQ(format("%0.1e", -1.93437090148818698e-297), "-1.9e-297"); + EXPECT_EQ(format("%0.1e", -9.92255780642280927e-298), "-9.9e-298"); + + // Rounding large negative exponent first digit + EXPECT_EQ(format("%0.1e", -8.956e-294), "-9.0e-294"); } TEST_F(FormatConvertTest, DoubleRoundA) {
diff --git a/absl/strings/resize_and_overwrite.h b/absl/strings/resize_and_overwrite.h index b3bd06e..169c685 100644 --- a/absl/strings/resize_and_overwrite.h +++ b/absl/strings/resize_and_overwrite.h
@@ -141,22 +141,8 @@ str.erase(static_cast<typename T::size_type>(new_size)); } -} // namespace strings_internal - -// Resizes `str` to contain at most `n` characters, using the user-provided -// operation `op` to modify the possibly indeterminate contents. `op` must -// return the finalized length of `str`. -// -// Invalidates all iterators, pointers, and references into `str`, regardless -// of whether reallocation occurs. -// -// `op(value_type* buf, size_t buf_size)` is allowed to write `value_type{}` to -// `buf[buf_size]`, which facilitiates interoperation with functions that write -// a trailing NUL. Please note that this requirement is more strict than -// `basic_string::resize_and_overwrite()`, which allows writing an abitrary -// value to `buf[buf_size]`. template <typename T, typename Op> -void StringResizeAndOverwrite(T& str, typename T::size_type n, Op op) { +void StringResizeAndOverwriteImpl(T& str, typename T::size_type n, Op op) { #ifdef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE str.resize_and_overwrite(n, std::move(op)); #else @@ -176,9 +162,27 @@ strings_internal::StringResizeAndOverwriteFallback(str, n, op); } #endif +} + +} // namespace strings_internal + +// Resizes `str` to contain at most `n` characters, using the user-provided +// operation `op` to modify the possibly indeterminate contents. `op` must +// return the finalized length of `str`. +// +// Invalidates all iterators, pointers, and references into `str`, regardless +// of whether reallocation occurs. +// +// `op(value_type* buf, size_t buf_size)` is allowed to write `value_type{}` to +// `buf[buf_size]`, which facilitiates interoperation with functions that write +// a trailing NUL. Please note that this requirement is more strict than +// `basic_string::resize_and_overwrite()`, which allows writing an abitrary +// value to `buf[buf_size]`. +template <typename T, typename Op> +void StringResizeAndOverwrite(T& str, typename T::size_type n, Op op) { + strings_internal::StringResizeAndOverwriteImpl(str, n, std::move(op)); #if defined(ABSL_HAVE_MEMORY_SANITIZER) - auto shadow = __msan_test_shadow(str.data(), str.size()); - ABSL_ASSERT(shadow == -1); + __msan_check_mem_is_initialized(str.data(), str.size()); #endif }
diff --git a/absl/strings/resize_and_overwrite_test.cc b/absl/strings/resize_and_overwrite_test.cc index 8adad2c..1070dec 100644 --- a/absl/strings/resize_and_overwrite_test.cc +++ b/absl/strings/resize_and_overwrite_test.cc
@@ -119,7 +119,8 @@ if (param.initial_size < param.final_size) { #ifndef NDEBUG - EXPECT_DEATH_IF_SUPPORTED(op(), "shadow == -1"); + EXPECT_DEATH_IF_SUPPORTED(op(), + "MemorySanitizer: use-of-uninitialized-value"); #endif } else { // The string is fully initialized from the initial constructor, or we skip
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 99b3a1e..546b8ae 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc
@@ -26,7 +26,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/nullability.h" -#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/internal/append_and_overwrite.h" #include "absl/strings/resize_and_overwrite.h" #include "absl/strings/string_view.h" @@ -53,11 +53,6 @@ return after; } -inline void STLStringAppendUninitializedAmortized(std::string* dest, - size_t to_append) { - strings_internal::AppendUninitializedTraits<std::string>::Append(dest, - to_append); -} } // namespace std::string StrCat(const AlphaNum& a, const AlphaNum& b) { @@ -165,49 +160,51 @@ void AppendPieces(std::string* absl_nonnull dest, std::initializer_list<absl::string_view> pieces) { - size_t old_size = dest->size(); size_t to_append = 0; for (absl::string_view piece : pieces) { ASSERT_NO_OVERLAP(*dest, piece); to_append += piece.size(); } - STLStringAppendUninitializedAmortized(dest, to_append); - - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - for (absl::string_view piece : pieces) { - const size_t this_size = piece.size(); - if (this_size != 0) { - memcpy(out, piece.data(), this_size); - out += this_size; - } - } - assert(out == begin + dest->size()); + StringAppendAndOverwrite(*dest, to_append, + [&pieces](char* const buf, size_t buf_size) { + char* out = buf; + for (absl::string_view piece : pieces) { + const size_t this_size = piece.size(); + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } + } + assert(out == buf + buf_size); + return buf_size; + }); } } // namespace strings_internal void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a) { ASSERT_NO_OVERLAP(*dest, a); - std::string::size_type old_size = dest->size(); - STLStringAppendUninitializedAmortized(dest, a.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - assert(out == begin + dest->size()); + strings_internal::StringAppendAndOverwrite( + *dest, a.size(), [&a](char* const buf, size_t buf_size) { + char* out = buf; + out = Append(out, a); + assert(out == buf + buf_size); + return buf_size; + }); } void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, const AlphaNum& b) { ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); - std::string::size_type old_size = dest->size(); - STLStringAppendUninitializedAmortized(dest, a.size() + b.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - assert(out == begin + dest->size()); + strings_internal::StringAppendAndOverwrite( + *dest, a.size() + b.size(), [&a, &b](char* const buf, size_t buf_size) { + char* out = buf; + out = Append(out, a); + out = Append(out, b); + assert(out == buf + buf_size); + return buf_size; + }); } void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, @@ -215,14 +212,16 @@ ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); - std::string::size_type old_size = dest->size(); - STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - assert(out == begin + dest->size()); + strings_internal::StringAppendAndOverwrite( + *dest, a.size() + b.size() + c.size(), + [&a, &b, &c](char* const buf, size_t buf_size) { + char* out = buf; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + assert(out == buf + buf_size); + return buf_size; + }); } void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, @@ -231,16 +230,17 @@ ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); ASSERT_NO_OVERLAP(*dest, d); - std::string::size_type old_size = dest->size(); - STLStringAppendUninitializedAmortized( - dest, a.size() + b.size() + c.size() + d.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - out = Append(out, d); - assert(out == begin + dest->size()); + strings_internal::StringAppendAndOverwrite( + *dest, a.size() + b.size() + c.size() + d.size(), + [&a, &b, &c, &d](char* const buf, size_t buf_size) { + char* out = buf; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + out = Append(out, d); + assert(out == buf + buf_size); + return buf_size; + }); } ABSL_NAMESPACE_END
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index 3c2ca5d..f5d600b 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc
@@ -26,7 +26,7 @@ #include "absl/base/nullability.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" -#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/internal/append_and_overwrite.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -85,29 +85,29 @@ if (size == 0) return; // Build the string. - size_t original_size = output->size(); - ABSL_INTERNAL_CHECK( - size <= std::numeric_limits<size_t>::max() - original_size, - "size_t overflow"); - strings_internal::STLStringResizeUninitializedAmortized(output, - original_size + size); - char* target = &(*output)[original_size]; - for (size_t i = 0; i < format.size(); i++) { - if (format[i] == '$') { - if (absl::ascii_isdigit(static_cast<unsigned char>(format[i + 1]))) { - const absl::string_view src = args_array[format[i + 1] - '0']; - target = std::copy(src.begin(), src.end(), target); - ++i; // Skip next char. - } else if (format[i + 1] == '$') { - *target++ = '$'; - ++i; // Skip next char. - } - } else { - *target++ = format[i]; - } - } - - assert(target == output->data() + output->size()); + ABSL_INTERNAL_CHECK(size <= output->max_size() - output->size(), + "Exceeds std::string::max_size()"); + strings_internal::StringAppendAndOverwrite( + *output, size, [format, args_array](char* const buf, size_t buf_size) { + char* target = buf; + for (size_t i = 0; i < format.size(); i++) { + if (format[i] == '$') { + if (absl::ascii_isdigit( + static_cast<unsigned char>(format[i + 1]))) { + const absl::string_view src = args_array[format[i + 1] - '0']; + target = std::copy(src.begin(), src.end(), target); + ++i; // Skip next char. + } else if (format[i + 1] == '$') { + *target++ = '$'; + ++i; // Skip next char. + } + } else { + *target++ = format[i]; + } + } + assert(target == buf + buf_size); + return buf_size; + }); } Arg::Arg(const void* absl_nullable value) {
diff --git a/absl/time/clock.cc b/absl/time/clock.cc index bf6a10b..2a5f41b 100644 --- a/absl/time/clock.cc +++ b/absl/time/clock.cc
@@ -338,18 +338,20 @@ // to the same shared data. seq_read0 = time_state.seq.load(std::memory_order_acquire); - base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed); + // The algorithm does not require that the following four loads be ordered + // with respect to one another; it requires only that they precede the load of + // time_state.seq below them. Nevertheless, we mark each of them as an + // acquire-load, rather than using a barrier immediately before the + // time_state.seq load, because the former is likely faster on most CPUs of + // interest. Architectures that may see a regression because of this approach + // include PowerPC and MIPS. + base_ns = time_state.last_sample.base_ns.load(std::memory_order_acquire); base_cycles = - time_state.last_sample.base_cycles.load(std::memory_order_relaxed); + time_state.last_sample.base_cycles.load(std::memory_order_acquire); nsscaled_per_cycle = - time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed); + time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_acquire); min_cycles_per_sample = time_state.last_sample.min_cycles_per_sample.load( - std::memory_order_relaxed); - - // This acquire fence pairs with the release fence in SeqAcquire. Since it - // is sequenced between reads of shared data and seq_read1, the reads of - // shared data are effectively acquiring. - std::atomic_thread_fence(std::memory_order_acquire); + std::memory_order_acquire); // The shared-data reads are effectively acquire ordered, and the // shared-data writes are effectively release ordered. Therefore if our
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh index f19cd50..4e73847 100755 --- a/ci/macos_xcode_bazel.sh +++ b/ci/macos_xcode_bazel.sh
@@ -37,8 +37,8 @@ # Use Bazel Vendor mode to reduce reliance on external dependencies. if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then - tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${TMP}/" - BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/abseil-cpp_vendor\" ${BAZEL_EXTRA_ARGS:-}" + tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${HOME}/" + BAZEL_EXTRA_ARGS="--vendor_dir=${HOME}/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi # Print the compiler and Bazel versions.