diff --git a/DEPS b/DEPS index 0fe61e5faf..f4c77ead38 100644 --- a/DEPS +++ b/DEPS @@ -10,12 +10,12 @@ vars = { 'checkout_configuration': 'default', 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"', 'webrtc_git': 'https://webrtc.googlesource.com', - 'chromium_revision': 'c92ed252174bc9b9ece9d11a83852f4ab8765575', + 'chromium_revision': 'bcf2616e8eb74191a038c9ad457344fa0354f420', 'boringssl_git': 'https://boringssl.googlesource.com', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. - 'swarming_revision': '88229872dd17e71658fe96763feaa77915d8cbd6', + 'swarming_revision': '833f5ebf894be1e3e6d13678d5de8479bf12ff28', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -27,7 +27,7 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'd8600ccc2ddeb2cc43ba6adccea9f687f5f1b2a9', + 'catapult_revision': 'ce9b3742a10dc2f4c796a1b26e73155d0bfa674a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -43,17 +43,17 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Chromium third_party # and whatever else without interference from each other. - 'chromium_third_party_revision': '51c08cf9af330cc4173d8e37974e49074431d5f4', + 'chromium_third_party_revision': '9d65a3cddae9b8340d4c77b1ae9034d4501935b8', } deps = { # TODO(kjellander): Move this to be Android-only once the libevent dependency # in base/third_party/libevent is solved. 'src/base': - Var('chromium_git') + '/chromium/src/base' + '@' + 'a7a2409f9b398da1abc5e7604a974a1fa2ade51d', + Var('chromium_git') + '/chromium/src/base' + '@' + 'b802985ef4661601e825640d1a566489cfcb6d8b', 'src/build': - Var('chromium_git') + '/chromium/src/build' + '@' + '03f39fd800ed8fd5fa1a8b43b5963c6fc063475b', + Var('chromium_git') + '/chromium/src/build' + '@' + 'fc8308f6b6c6212c6be8d2769c721611d5253b49', 'src/buildtools': - Var('chromium_git') + '/chromium/buildtools.git' + '@' + 'a9e946f166b73f9dc170129f6586a1e68efb0ab3', + Var('chromium_git') + '/chromium/buildtools.git' + '@' + '94288c26d2ffe3aec9848c147839afee597acefd', # Gradle 4.3-rc4. Used for testing Android Studio project generation for WebRTC. 'src/examples/androidtests/third_party/gradle': { 'url': Var('chromium_git') + '/external/github.com/gradle/gradle.git' + '@' + @@ -61,11 +61,11 @@ deps = { 'condition': 'checkout_android', }, 'src/ios': { - 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + 'e070a9306253c327361423e1fce2ae02c419f6ba', + 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '289c450460f6a2faf57d1ee011ef7595691dd25b', 'condition': 'checkout_ios', }, 'src/testing': - Var('chromium_git') + '/chromium/src/testing' + '@' + 'f5b31b58c69ca3bbcfe81d8c2028063931f6681e', + Var('chromium_git') + '/chromium/src/testing' + '@' + 'a5fce03148805a479c78b685b31f5a2392218ffd', # This entry is used for chromium third_party rolling into webrtc third_party only. 'src/third_party_chromium': { 'url': Var('chromium_git') + '/chromium/src/third_party' + '@' + Var('chromium_third_party_revision'), @@ -94,7 +94,7 @@ deps = { 'src/third_party/colorama/src': Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8de3800ce55ba459ffcbedcfa52ef5e6e59caab6', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8fe4d8cbef3bff9d615de14d9a414679cf9ca8c3', 'src/third_party/errorprone/lib': { 'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '980d49e839aa4984015efed34b0134d4b2c9b6d7', 'condition': 'checkout_android', @@ -113,7 +113,7 @@ deps = { 'src/third_party/gtest-parallel': Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + 'cb3514a0858be0f66281d892e2242d1073fd75fe', 'src/third_party/googletest/src': - Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '045e7f9ee4f969ac1a3fe428f79c4b880f0aff43', + Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '08d5b1f33af8c18785fb8ca02792b5fac81e248f', 'src/third_party/icu': { 'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f61e46dbee9d539a32551493e3bcc1dea92f83ec', }, @@ -175,7 +175,7 @@ deps = { 'src/third_party/yasm/source/patched-yasm': Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc', 'src/tools': - Var('chromium_git') + '/chromium/src/tools' + '@' + 'e0247206293ec06cc0aee950384e13721cd55d86', + Var('chromium_git') + '/chromium/src/tools' + '@' + '6e6e39868794fc2bfeaf64502ad903be79616a0b', 'src/tools/gyp': Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb', 'src/tools/swarming_client': diff --git a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake index 0520fba3f0..e4eafe49e4 100644 --- a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake +++ b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake @@ -16,6 +16,11 @@ include(CMakeParseArguments) +# The IDE folder for Abseil that will be used if Abseil is included in a CMake +# project that sets +# set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# For example, Visual Studio supports folders. +set(ABSL_IDE_FOLDER Abseil) # # create a library in the absl namespace @@ -49,6 +54,8 @@ function(absl_library) PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS} PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS} ) + # Add all Abseil targets to a a folder in the IDE for organization. + set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) if(ABSL_LIB_EXPORT_NAME) add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME}) @@ -93,6 +100,9 @@ function(absl_header_library) PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS} ) + # Add all Abseil targets to a a folder in the IDE for organization. + set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) + if(ABSL_HO_LIB_EXPORT_NAME) add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME}) endif() @@ -139,7 +149,10 @@ function(absl_test) PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} ) - add_test(${_NAME}_test ${_NAME}_bin) + # Add all Abseil targets to a a folder in the IDE for organization. + set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER}) + + add_test(${_NAME} ${_NAME}_bin) endif(BUILD_TESTING) endfunction() diff --git a/third_party/abseil-cpp/CMake/CMakeLists.txt.in b/third_party/abseil-cpp/CMake/CMakeLists.txt.in new file mode 100644 index 0000000000..d60a33e9ac --- /dev/null +++ b/third_party/abseil-cpp/CMake/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) \ No newline at end of file diff --git a/third_party/abseil-cpp/CMake/DownloadGTest.cmake b/third_party/abseil-cpp/CMake/DownloadGTest.cmake new file mode 100644 index 0000000000..9d4132158b --- /dev/null +++ b/third_party/abseil-cpp/CMake/DownloadGTest.cmake @@ -0,0 +1,32 @@ +# Downloads and unpacks googletest at configure time. Based on the instructions +# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project + +# Download the latest googletest from Github master +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in + googletest-download/CMakeLists.txt +) + +# Configure and build the downloaded googletest source +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() + +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines the gtest and gtest_main +# targets. +add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) diff --git a/third_party/abseil-cpp/CMake/README.md b/third_party/abseil-cpp/CMake/README.md index e99340cc6b..79bbe24d5a 100644 --- a/third_party/abseil-cpp/CMake/README.md +++ b/third_party/abseil-cpp/CMake/README.md @@ -52,14 +52,42 @@ if(MSVC) add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS) endif() -add_subdirectory(googletest) -add_subdirectory(cctz) add_subdirectory(abseil-cpp) add_executable(my_exe source.cpp) target_link_libraries(my_exe absl::base absl::synchronization absl::strings) ``` +### Running Abseil Tests with CMake + +Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run. + +You will need to provide Abseil with a Googletest dependency. There are two +options for how to do this: + +* Use `-DABSL_USE_GOOGLETEST_HEAD`. This will automatically download the latest +Googletest source into the build directory at configure time. Googletest will +then be compiled directly alongside Abseil's tests. +* Manually integrate Googletest with your build. See +https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake +for more information on using Googletest in a CMake project. + +For example, to run just the Abseil tests, you could use this script: + +``` +cd path/to/abseil-cpp +mkdir build +cd build +cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON .. +make -j +ctest +``` + +Currently, we only run our tests with CMake in a Linux environment, but we are +working on the rest of our supported platforms. See +https://github.com/abseil/abseil-cpp/projects/1 and +https://github.com/abseil/abseil-cpp/issues/109 for more information. + ### Available Abseil CMake Public Targets Here's a non-exhaustive list of Abseil CMake public targets: diff --git a/third_party/abseil-cpp/CMakeLists.txt b/third_party/abseil-cpp/CMakeLists.txt index e46bdf455e..744241efc1 100644 --- a/third_party/abseil-cpp/CMakeLists.txt +++ b/third_party/abseil-cpp/CMakeLists.txt @@ -16,9 +16,6 @@ cmake_minimum_required(VERSION 2.8.12) project(absl) -# enable ctest -include(CTest) - list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake) include(GNUInstallDirs) @@ -56,7 +53,6 @@ list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) # -std=X set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_WARNING_VLA} ${CMAKE_CXX_FLAGS} ") # -fexceptions set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}") @@ -65,12 +61,25 @@ set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}") ## pthread find_package(Threads REQUIRED) -# commented: used only for standalone test -# Don't remove these or else CMake CI will break -#add_subdirectory(googletest) +option(ABSL_USE_GOOGLETEST_HEAD + "If ON, abseil will download HEAD from googletest at config time." OFF) + +option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF) + +if(${ABSL_RUN_TESTS}) + # enable CTest. This will set BUILD_TESTING to ON unless otherwise specified + # on the command line + include(CTest) + enable_testing() +endif() ## check targets if(BUILD_TESTING) + + if(${ABSL_USE_GOOGLETEST_HEAD}) + include(CMake/DownloadGTest.cmake) + endif() + check_target(gtest) check_target(gtest_main) check_target(gmock) diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index 1c3b40a8db..84f9b0b665 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium @@ -4,7 +4,7 @@ URL: https://github.com/abseil/abseil-cpp License: Apache 2.0 License File: LICENSE Version: 0 -Revision: af7882601aad93ada881486eeaabc562f1733961 +Revision: 30de20488bb88dc22d23521c5c222ec6d924e289 Security Critical: yes Description: diff --git a/third_party/abseil-cpp/WORKSPACE b/third_party/abseil-cpp/WORKSPACE index 0546573f32..064459306d 100644 --- a/third_party/abseil-cpp/WORKSPACE +++ b/third_party/abseil-cpp/WORKSPACE @@ -3,11 +3,11 @@ workspace(name = "com_google_absl") http_archive( name = "bazel_toolchains", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz", - "https://github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz", ], - strip_prefix = "bazel-toolchains-r324073", - sha256 = "71548c0d6cd53eddebbde4fa9962f5395e82645fb9992719e0890505b177f245", + strip_prefix = "bazel-toolchains-f8847f64e6950e8ab9fde1c0aba768550b0d9ab2", + sha256 = "794366f51fea224b3656a0b0f8f1518e739748646523a572fcd3d68614a0e670", ) # GoogleTest/GoogleMock framework. Used by most unit-tests. @@ -17,6 +17,13 @@ http_archive( strip_prefix = "googletest-master", ) +# Google benchmark. +http_archive( + name = "com_github_google_benchmark", + urls = ["https://github.com/google/benchmark/archive/master.zip"], + strip_prefix = "benchmark-master", +) + # RE2 regular-expression framework. Used by some unit-tests. http_archive( name = "com_googlesource_code_re2", diff --git a/third_party/abseil-cpp/absl/algorithm/BUILD.bazel b/third_party/abseil-cpp/absl/algorithm/BUILD.bazel index 255b986e9a..3b24ce1202 100644 --- a/third_party/abseil-cpp/absl/algorithm/BUILD.bazel +++ b/third_party/abseil-cpp/absl/algorithm/BUILD.bazel @@ -41,6 +41,18 @@ cc_test( ], ) +cc_test( + name = "algorithm_benchmark", + srcs = ["equal_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + deps = [ + ":algorithm", + "//absl/base:core_headers", + "@com_github_google_benchmark//:benchmark", + ], +) + cc_library( name = "container", hdrs = [ diff --git a/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc b/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc new file mode 100644 index 0000000000..9af36ce79f --- /dev/null +++ b/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc @@ -0,0 +1,128 @@ +// Copyright 2017 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 +// +// http://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 +#include + +#include "benchmark/benchmark.h" +#include "absl/algorithm/algorithm.h" + +namespace { + +// The range of sequence sizes to benchmark. +constexpr int kMinBenchmarkSize = 1024; +constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024; + +// A user-defined type for use in equality benchmarks. Note that we expect +// std::memcmp to win for this type: libstdc++'s std::equal only defers to +// memcmp for integral types. This is because it is not straightforward to +// guarantee that std::memcmp would produce a result "as-if" compared by +// operator== for other types (example gotchas: NaN floats, structs with +// padding). +struct EightBits { + explicit EightBits(int /* unused */) : data(0) {} + bool operator==(const EightBits& rhs) const { return data == rhs.data; } + uint8_t data; +}; + +template +void BM_absl_equal_benchmark(benchmark::State& state) { + std::vector xs(state.range(0), T(0)); + std::vector ys = xs; + while (state.KeepRunning()) { + const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end()); + benchmark::DoNotOptimize(same); + } +} + +template +void BM_std_equal_benchmark(benchmark::State& state) { + std::vector xs(state.range(0), T(0)); + std::vector ys = xs; + while (state.KeepRunning()) { + const bool same = std::equal(xs.begin(), xs.end(), ys.begin()); + benchmark::DoNotOptimize(same); + } +} + +template +void BM_memcmp_benchmark(benchmark::State& state) { + std::vector xs(state.range(0), T(0)); + std::vector ys = xs; + while (state.KeepRunning()) { + const bool same = + std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0; + benchmark::DoNotOptimize(same); + } +} + +// The expectation is that the compiler should be able to elide the equality +// comparison altogether for sufficiently simple types. +template +void BM_absl_equal_self_benchmark(benchmark::State& state) { + std::vector xs(state.range(0), T(0)); + while (state.KeepRunning()) { + const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end()); + benchmark::DoNotOptimize(same); + } +} + +BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); + +BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); + +BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); + +BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); + +BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); +BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits) + ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel index f9aac5a5aa..5c05c67831 100644 --- a/third_party/abseil-cpp/absl/base/BUILD.bazel +++ b/third_party/abseil-cpp/absl/base/BUILD.bazel @@ -147,6 +147,18 @@ cc_library( ], ) +cc_test( + name = "atomic_hook_test", + size = "small", + srcs = ["internal/atomic_hook_test.cc"], + copts = ABSL_TEST_COPTS, + deps = [ + ":base", + ":core_headers", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "bit_cast_test", size = "small", @@ -393,3 +405,16 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "thread_identity_benchmark", + srcs = ["internal/thread_identity_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + visibility = ["//visibility:private"], + deps = [ + ":base", + "//absl/synchronization", + "@com_github_google_benchmark//:benchmark", + ], +) diff --git a/third_party/abseil-cpp/absl/base/CMakeLists.txt b/third_party/abseil-cpp/absl/base/CMakeLists.txt index 329a3d0555..4564056278 100644 --- a/third_party/abseil-cpp/absl/base/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/base/CMakeLists.txt @@ -99,14 +99,18 @@ absl_library( if(BUILD_TESTING) # exception-safety testing library - set(EXCEPTION_SAFETY_TESTING_SRC "internal/exception_safety_testing.cc") + set(EXCEPTION_SAFETY_TESTING_SRC + "internal/exception_safety_testing.h" + "internal/exception_safety_testing.cc" + ) set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES ${ABSL_TEST_COMMON_LIBRARIES} absl::base absl::memory absl::meta absl::strings - absl::types + absl::optional + gtest ) absl_library( @@ -116,6 +120,8 @@ absl_library( ${EXCEPTION_SAFETY_TESTING_SRC} PUBLIC_LIBRARIES ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES} + PRIVATE_COMPILE_FLAGS + ${ABSL_EXCEPTIONS_FLAG} ) endif() @@ -162,6 +168,20 @@ absl_library( ## TESTS # +# call once test +set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc") +set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base) + +absl_test( + TARGET + atomic_hook_test + SOURCES + ${ATOMIC_HOOK_TEST_SRC} + PUBLIC_LIBRARIES + ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES} +) + + # call once test set(CALL_ONCE_TEST_SRC "call_once_test.cc") set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) @@ -344,7 +364,14 @@ absl_test( #test exceptions_safety_testing_test set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc") -set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES absl::base absl::memory absl::meta absl::strings absl::optional) +set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES + absl::base + absl_base_internal_exception_safety_testing + absl::memory + absl::meta + absl::strings + absl::optional +) absl_test( TARGET diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h index a4ec7e7c97..b1883b6d75 100644 --- a/third_party/abseil-cpp/absl/base/attributes.h +++ b/third_party/abseil-cpp/absl/base/attributes.h @@ -52,7 +52,8 @@ // Example: // // // Enable branches in the Abseil code that are tagged for ASan: -// $ bazel -D ADDRESS_SANITIZER -fsanitize=address *target* +// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address +// --linkopt=-fsanitize=address *target* // // Since these macro names are only supported by GCC and Clang, we only check // for `__GNUC__` (GCC or Clang) and the above macros. diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc index ae6ec0f775..b97fa3a8b4 100644 --- a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc +++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc @@ -32,7 +32,7 @@ /* Each function is empty and called (via a macro) only in debug mode. The arguments are captured by dynamic tools at runtime. */ -#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 +#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__) #if __has_feature(memory_sanitizer) #include diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/third_party/abseil-cpp/absl/base/dynamic_annotations.h index 88048b0fbb..b308e93370 100644 --- a/third_party/abseil-cpp/absl/base/dynamic_annotations.h +++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.h @@ -191,16 +191,16 @@ #elif defined(ABSL_ANNOTALYSIS_ENABLED) #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ - AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) + StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) #define ABSL_ANNOTATE_IGNORE_READS_END() \ - AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) + StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ - AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) + StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ - AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) + StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) #else #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ @@ -282,13 +282,13 @@ void AbslAnnotateIgnoreWritesEnd(const char *file, int line); allows IGNORE_READS_AND_WRITES to work properly. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" -static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line) +static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line) ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line) +static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line) ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreWritesBegin( +static inline void StaticAnnotateIgnoreWritesBegin( const char *file, int line) { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreWritesEnd( +static inline void StaticAnnotateIgnoreWritesEnd( const char *file, int line) { (void)file; (void)line; } #pragma GCC diagnostic pop #endif diff --git a/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc b/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc index 94a7e4f748..a8b82b73da 100644 --- a/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc +++ b/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc @@ -25,11 +25,13 @@ #include "gtest/gtest.h" #include "absl/memory/memory.h" -namespace absl { +namespace testing { + namespace { -using ::absl::exceptions_internal::SetCountdown; -using ::absl::exceptions_internal::TestException; -using ::absl::exceptions_internal::UnsetCountdown; + +using ::testing::exceptions_internal::SetCountdown; +using ::testing::exceptions_internal::TestException; +using ::testing::exceptions_internal::UnsetCountdown; // EXPECT_NO_THROW can't inspect the thrown inspection in general. template @@ -41,15 +43,7 @@ void ExpectNoThrow(const F& f) { } } -class ThrowingValueTest : public ::testing::Test { - protected: - void SetUp() override { UnsetCountdown(); } - - private: - ConstructorTracker clouseau_; -}; - -TEST_F(ThrowingValueTest, Throws) { +TEST(ThrowingValueTest, Throws) { SetCountdown(); EXPECT_THROW(ThrowingValue<> bomb, TestException); @@ -60,6 +54,8 @@ TEST_F(ThrowingValueTest, Throws) { ExpectNoThrow([]() { ThrowingValue<> bomb; }); ExpectNoThrow([]() { ThrowingValue<> bomb; }); EXPECT_THROW(ThrowingValue<> bomb, TestException); + + UnsetCountdown(); } // Tests that an operation throws when the countdown is at 0, doesn't throw when @@ -67,7 +63,6 @@ TEST_F(ThrowingValueTest, Throws) { // ThrowingValue if it throws template void TestOp(const F& f) { - UnsetCountdown(); ExpectNoThrow(f); SetCountdown(); @@ -75,7 +70,7 @@ void TestOp(const F& f) { UnsetCountdown(); } -TEST_F(ThrowingValueTest, ThrowingCtors) { +TEST(ThrowingValueTest, ThrowingCtors) { ThrowingValue<> bomb; TestOp([]() { ThrowingValue<> bomb(1); }); @@ -83,14 +78,35 @@ TEST_F(ThrowingValueTest, ThrowingCtors) { TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); }); } -TEST_F(ThrowingValueTest, ThrowingAssignment) { +TEST(ThrowingValueTest, ThrowingAssignment) { ThrowingValue<> bomb, bomb1; TestOp([&]() { bomb = bomb1; }); TestOp([&]() { bomb = std::move(bomb1); }); + + // Test that when assignment throws, the assignment should fail (lhs != rhs) + // and strong guarantee fails (lhs != lhs_copy). + { + ThrowingValue<> lhs(39), rhs(42); + ThrowingValue<> lhs_copy(lhs); + SetCountdown(); + EXPECT_THROW(lhs = rhs, TestException); + UnsetCountdown(); + EXPECT_NE(lhs, rhs); + EXPECT_NE(lhs_copy, lhs); + } + { + ThrowingValue<> lhs(39), rhs(42); + ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs); + SetCountdown(); + EXPECT_THROW(lhs = std::move(rhs), TestException); + UnsetCountdown(); + EXPECT_NE(lhs, rhs_copy); + EXPECT_NE(lhs_copy, lhs); + } } -TEST_F(ThrowingValueTest, ThrowingComparisons) { +TEST(ThrowingValueTest, ThrowingComparisons) { ThrowingValue<> bomb1, bomb2; TestOp([&]() { return bomb1 == bomb2; }); TestOp([&]() { return bomb1 != bomb2; }); @@ -100,7 +116,7 @@ TEST_F(ThrowingValueTest, ThrowingComparisons) { TestOp([&]() { return bomb1 >= bomb2; }); } -TEST_F(ThrowingValueTest, ThrowingArithmeticOps) { +TEST(ThrowingValueTest, ThrowingArithmeticOps) { ThrowingValue<> bomb1(1), bomb2(2); TestOp([&bomb1]() { +bomb1; }); @@ -118,7 +134,7 @@ TEST_F(ThrowingValueTest, ThrowingArithmeticOps) { TestOp([&]() { bomb1 >> 1; }); } -TEST_F(ThrowingValueTest, ThrowingLogicalOps) { +TEST(ThrowingValueTest, ThrowingLogicalOps) { ThrowingValue<> bomb1, bomb2; TestOp([&bomb1]() { !bomb1; }); @@ -126,7 +142,7 @@ TEST_F(ThrowingValueTest, ThrowingLogicalOps) { TestOp([&]() { bomb1 || bomb2; }); } -TEST_F(ThrowingValueTest, ThrowingBitwiseOps) { +TEST(ThrowingValueTest, ThrowingBitwiseOps) { ThrowingValue<> bomb1, bomb2; TestOp([&bomb1]() { ~bomb1; }); @@ -135,7 +151,7 @@ TEST_F(ThrowingValueTest, ThrowingBitwiseOps) { TestOp([&]() { bomb1 ^ bomb2; }); } -TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) { +TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) { ThrowingValue<> bomb1(1), bomb2(2); TestOp([&]() { bomb1 += bomb2; }); @@ -149,7 +165,7 @@ TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) { TestOp([&]() { bomb1 *= bomb2; }); } -TEST_F(ThrowingValueTest, ThrowingStreamOps) { +TEST(ThrowingValueTest, ThrowingStreamOps) { ThrowingValue<> bomb; TestOp([&]() { std::cin >> bomb; }); @@ -158,7 +174,6 @@ TEST_F(ThrowingValueTest, ThrowingStreamOps) { template void TestAllocatingOp(const F& f) { - UnsetCountdown(); ExpectNoThrow(f); SetCountdown(); @@ -166,62 +181,90 @@ void TestAllocatingOp(const F& f) { UnsetCountdown(); } -TEST_F(ThrowingValueTest, ThrowingAllocatingOps) { +TEST(ThrowingValueTest, ThrowingAllocatingOps) { // make_unique calls unqualified operator new, so these exercise the // ThrowingValue overloads. TestAllocatingOp([]() { return absl::make_unique>(1); }); TestAllocatingOp([]() { return absl::make_unique[]>(2); }); } -TEST_F(ThrowingValueTest, NonThrowingMoveCtor) { - ThrowingValue nothrow_ctor; +TEST(ThrowingValueTest, NonThrowingMoveCtor) { + ThrowingValue nothrow_ctor; SetCountdown(); ExpectNoThrow([¬hrow_ctor]() { - ThrowingValue nothrow1 = std::move(nothrow_ctor); + ThrowingValue nothrow1 = std::move(nothrow_ctor); }); + UnsetCountdown(); } -TEST_F(ThrowingValueTest, NonThrowingMoveAssign) { - ThrowingValue nothrow_assign1, nothrow_assign2; +TEST(ThrowingValueTest, NonThrowingMoveAssign) { + ThrowingValue nothrow_assign1, nothrow_assign2; SetCountdown(); ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { nothrow_assign1 = std::move(nothrow_assign2); }); + UnsetCountdown(); } -TEST_F(ThrowingValueTest, ThrowingSwap) { +TEST(ThrowingValueTest, ThrowingCopyCtor) { + ThrowingValue<> tv; + + TestOp([&]() { ThrowingValue<> tv_copy(tv); }); +} + +TEST(ThrowingValueTest, ThrowingCopyAssign) { + ThrowingValue<> tv1, tv2; + + TestOp([&]() { tv1 = tv2; }); +} + +TEST(ThrowingValueTest, NonThrowingCopyCtor) { + ThrowingValue nothrow_ctor; + + SetCountdown(); + ExpectNoThrow([¬hrow_ctor]() { + ThrowingValue nothrow1(nothrow_ctor); + }); + UnsetCountdown(); +} + +TEST(ThrowingValueTest, NonThrowingCopyAssign) { + ThrowingValue nothrow_assign1, nothrow_assign2; + + SetCountdown(); + ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { + nothrow_assign1 = nothrow_assign2; + }); + UnsetCountdown(); +} + +TEST(ThrowingValueTest, ThrowingSwap) { ThrowingValue<> bomb1, bomb2; TestOp([&]() { std::swap(bomb1, bomb2); }); - - ThrowingValue bomb3, bomb4; - TestOp([&]() { std::swap(bomb3, bomb4); }); - - ThrowingValue bomb5, bomb6; - TestOp([&]() { std::swap(bomb5, bomb6); }); } -TEST_F(ThrowingValueTest, NonThrowingSwap) { - ThrowingValue bomb1, bomb2; +TEST(ThrowingValueTest, NonThrowingSwap) { + ThrowingValue bomb1, bomb2; ExpectNoThrow([&]() { std::swap(bomb1, bomb2); }); } -TEST_F(ThrowingValueTest, NonThrowingAllocation) { - ThrowingValue* allocated; - ThrowingValue* array; +TEST(ThrowingValueTest, NonThrowingAllocation) { + ThrowingValue* allocated; + ThrowingValue* array; ExpectNoThrow([&allocated]() { - allocated = new ThrowingValue(1); + allocated = new ThrowingValue(1); delete allocated; }); ExpectNoThrow([&array]() { - array = new ThrowingValue[2]; + array = new ThrowingValue[2]; delete[] array; }); } -TEST_F(ThrowingValueTest, NonThrowingDelete) { +TEST(ThrowingValueTest, NonThrowingDelete) { auto* allocated = new ThrowingValue<>(1); auto* array = new ThrowingValue<>[2]; @@ -229,12 +272,14 @@ TEST_F(ThrowingValueTest, NonThrowingDelete) { ExpectNoThrow([allocated]() { delete allocated; }); SetCountdown(); ExpectNoThrow([array]() { delete[] array; }); + + UnsetCountdown(); } using Storage = absl::aligned_storage_t), alignof(ThrowingValue<>)>; -TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) { +TEST(ThrowingValueTest, NonThrowingPlacementDelete) { constexpr int kArrayLen = 2; // We intentionally create extra space to store the tag allocated by placement // new[]. @@ -256,16 +301,19 @@ TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) { for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>(); ThrowingValue<>::operator delete[](placed_array, &array_buf); }); + + UnsetCountdown(); } -TEST_F(ThrowingValueTest, NonThrowingDestructor) { +TEST(ThrowingValueTest, NonThrowingDestructor) { auto* allocated = new ThrowingValue<>(); + SetCountdown(); ExpectNoThrow([allocated]() { delete allocated; }); + UnsetCountdown(); } TEST(ThrowingBoolTest, ThrowingBool) { - UnsetCountdown(); ThrowingBool t = true; // Test that it's contextually convertible to bool @@ -276,15 +324,7 @@ TEST(ThrowingBoolTest, ThrowingBool) { TestOp([&]() { (void)!t; }); } -class ThrowingAllocatorTest : public ::testing::Test { - protected: - void SetUp() override { UnsetCountdown(); } - - private: - ConstructorTracker borlu_; -}; - -TEST_F(ThrowingAllocatorTest, MemoryManagement) { +TEST(ThrowingAllocatorTest, MemoryManagement) { // Just exercise the memory management capabilities under LSan to make sure we // don't leak. ThrowingAllocator int_alloc; @@ -293,24 +333,26 @@ TEST_F(ThrowingAllocatorTest, MemoryManagement) { int* i_array = int_alloc.allocate(2); int_alloc.deallocate(i_array, 2); - ThrowingAllocator> ef_alloc; - ThrowingValue<>* efp = ef_alloc.allocate(1); - ef_alloc.deallocate(efp, 1); - ThrowingValue<>* ef_array = ef_alloc.allocate(2); - ef_alloc.deallocate(ef_array, 2); + ThrowingAllocator> tv_alloc; + ThrowingValue<>* ptr = tv_alloc.allocate(1); + tv_alloc.deallocate(ptr, 1); + ThrowingValue<>* tv_array = tv_alloc.allocate(2); + tv_alloc.deallocate(tv_array, 2); } -TEST_F(ThrowingAllocatorTest, CallsGlobalNew) { - ThrowingAllocator, NoThrow::kNoThrow> nothrow_alloc; +TEST(ThrowingAllocatorTest, CallsGlobalNew) { + ThrowingAllocator, AllocSpec::kNoThrowAllocate> nothrow_alloc; ThrowingValue<>* ptr; SetCountdown(); // This will only throw if ThrowingValue::new is called. ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); nothrow_alloc.deallocate(ptr, 1); + + UnsetCountdown(); } -TEST_F(ThrowingAllocatorTest, ThrowingConstructors) { +TEST(ThrowingAllocatorTest, ThrowingConstructors) { ThrowingAllocator int_alloc; int* ip = nullptr; @@ -323,22 +365,27 @@ TEST_F(ThrowingAllocatorTest, ThrowingConstructors) { EXPECT_THROW(int_alloc.construct(ip, 2), TestException); EXPECT_EQ(*ip, 1); int_alloc.deallocate(ip, 1); + + UnsetCountdown(); } -TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) { +TEST(ThrowingAllocatorTest, NonThrowingConstruction) { { - ThrowingAllocator int_alloc; + ThrowingAllocator int_alloc; int* ip = nullptr; SetCountdown(); ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); + SetCountdown(); ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); + EXPECT_EQ(*ip, 2); int_alloc.deallocate(ip, 1); + + UnsetCountdown(); } - UnsetCountdown(); { ThrowingAllocator int_alloc; int* ip = nullptr; @@ -348,37 +395,45 @@ TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) { int_alloc.deallocate(ip, 1); } - UnsetCountdown(); { - ThrowingAllocator, NoThrow::kNoThrow> - ef_alloc; - ThrowingValue* efp; + ThrowingAllocator, AllocSpec::kNoThrowAllocate> + nothrow_alloc; + ThrowingValue<>* ptr; + SetCountdown(); - ExpectNoThrow([&]() { efp = ef_alloc.allocate(1); }); + ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); + SetCountdown(); - ExpectNoThrow([&]() { ef_alloc.construct(efp, 2); }); - EXPECT_EQ(efp->Get(), 2); - ef_alloc.destroy(efp); - ef_alloc.deallocate(efp, 1); + ExpectNoThrow( + [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); }); + + EXPECT_EQ(ptr->Get(), 2); + nothrow_alloc.destroy(ptr); + nothrow_alloc.deallocate(ptr, 1); + + UnsetCountdown(); } - UnsetCountdown(); { ThrowingAllocator a; + SetCountdown(); ExpectNoThrow([&]() { ThrowingAllocator a1 = a; }); + SetCountdown(); ExpectNoThrow([&]() { ThrowingAllocator a1 = std::move(a); }); + + UnsetCountdown(); } } -TEST_F(ThrowingAllocatorTest, ThrowingAllocatorConstruction) { +TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) { ThrowingAllocator a; TestOp([]() { ThrowingAllocator a; }); TestOp([&]() { a.select_on_container_copy_construction(); }); } -TEST_F(ThrowingAllocatorTest, State) { +TEST(ThrowingAllocatorTest, State) { ThrowingAllocator a1, a2; EXPECT_NE(a1, a2); @@ -390,13 +445,13 @@ TEST_F(ThrowingAllocatorTest, State) { EXPECT_EQ(a3, a1); } -TEST_F(ThrowingAllocatorTest, InVector) { +TEST(ThrowingAllocatorTest, InVector) { std::vector, ThrowingAllocator>> v; for (int i = 0; i < 20; ++i) v.push_back({}); for (int i = 0; i < 20; ++i) v.pop_back(); } -TEST_F(ThrowingAllocatorTest, InList) { +TEST(ThrowingAllocatorTest, InList) { std::list, ThrowingAllocator>> l; for (int i = 0; i < 20; ++i) l.push_back({}); for (int i = 0; i < 20; ++i) l.pop_back(); @@ -443,15 +498,15 @@ TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { // Test that providing operation and inveriants still does not allow for the // the invocation of .Test() and .Test(op) because it lacks a factory auto without_fac = - absl::MakeExceptionSafetyTester().WithOperation(op).WithInvariants( - inv, absl::strong_guarantee); + testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants( + inv, testing::strong_guarantee); EXPECT_FALSE(HasNullaryTest(without_fac)); EXPECT_FALSE(HasUnaryTest(without_fac)); // Test that providing invariants and factory allows the invocation of // .Test(op) but does not allow for .Test() because it lacks an operation - auto without_op = absl::MakeExceptionSafetyTester() - .WithInvariants(inv, absl::strong_guarantee) + auto without_op = testing::MakeExceptionSafetyTester() + .WithInvariants(inv, testing::strong_guarantee) .WithFactory(fac); EXPECT_FALSE(HasNullaryTest(without_op)); EXPECT_TRUE(HasUnaryTest(without_op)); @@ -459,7 +514,7 @@ TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { // Test that providing operation and factory still does not allow for the // the invocation of .Test() and .Test(op) because it lacks invariants auto without_inv = - absl::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); + testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); EXPECT_FALSE(HasNullaryTest(without_inv)); EXPECT_FALSE(HasUnaryTest(without_inv)); } @@ -504,28 +559,28 @@ auto example_lambda_invariant = [](ExampleStruct* example_struct) { // lambdas can all be used with ExceptionSafetyTester TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) { // function reference - EXPECT_TRUE(absl::MakeExceptionSafetyTester() + EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(ExampleFunctionFactory) .WithOperation(ExampleFunctionOperation) .WithInvariants(ExampleFunctionInvariant) .Test()); // function pointer - EXPECT_TRUE(absl::MakeExceptionSafetyTester() + EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(&ExampleFunctionFactory) .WithOperation(&ExampleFunctionOperation) .WithInvariants(&ExampleFunctionInvariant) .Test()); // struct - EXPECT_TRUE(absl::MakeExceptionSafetyTester() + EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(example_struct_factory) .WithOperation(example_struct_operation) .WithInvariants(example_struct_invariant) .Test()); // lambda - EXPECT_TRUE(absl::MakeExceptionSafetyTester() + EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(example_lambda_factory) .WithOperation(example_lambda_operation) .WithInvariants(example_lambda_invariant) @@ -553,9 +608,9 @@ struct { } invoker; auto tester = - absl::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants( + testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants( CheckNonNegativeInvariants); -auto strong_tester = tester.WithInvariants(absl::strong_guarantee); +auto strong_tester = tester.WithInvariants(testing::strong_guarantee); struct FailsBasicGuarantee : public NonNegative { void operator()() { @@ -659,7 +714,7 @@ TEST(ExceptionCheckTest, ModifyingChecker) { EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}) .WithInvariants(increment) .Test()); - EXPECT_TRUE(absl::MakeExceptionSafetyTester() + EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithInitialValue(HasReset{}) .WithInvariants(CheckHasResetInvariants) .Test(invoker)); @@ -734,7 +789,7 @@ template unsigned char ExhaustivenessTester::successes = 0; TEST(ExceptionCheckTest, Exhaustiveness) { - auto exhaust_tester = absl::MakeExceptionSafetyTester() + auto exhaust_tester = testing::MakeExceptionSafetyTester() .WithInvariants(CheckExhaustivenessTesterInvariants) .WithOperation(invoker); @@ -744,7 +799,7 @@ TEST(ExceptionCheckTest, Exhaustiveness) { EXPECT_TRUE( exhaust_tester.WithInitialValue(ExhaustivenessTester>{}) - .WithInvariants(absl::strong_guarantee) + .WithInvariants(testing::strong_guarantee) .Test()); EXPECT_EQ(ExhaustivenessTester>::successes, 0xF); } @@ -763,7 +818,7 @@ struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject { int LeaksIfCtorThrows::counter = 0; TEST(ExceptionCheckTest, TestLeakyCtor) { - absl::TestThrowingCtor(); + testing::TestThrowingCtor(); EXPECT_EQ(LeaksIfCtorThrows::counter, 1); LeaksIfCtorThrows::counter = 0; } @@ -772,19 +827,28 @@ struct Tracked : private exceptions_internal::TrackedObject { Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {} }; -TEST(ConstructorTrackerTest, Pass) { - ConstructorTracker javert; - Tracked t; +TEST(ConstructorTrackerTest, CreatedBefore) { + Tracked a, b, c; + exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); } -TEST(ConstructorTrackerTest, NotDestroyed) { +TEST(ConstructorTrackerTest, CreatedAfter) { + exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); + Tracked a, b, c; +} + +TEST(ConstructorTrackerTest, NotDestroyedAfter) { absl::aligned_storage_t storage; EXPECT_NONFATAL_FAILURE( { - ConstructorTracker gadget; + exceptions_internal::ConstructorTracker ct( + exceptions_internal::countdown); new (&storage) Tracked; }, "not destroyed"); + + // Manual destruction of the Tracked instance is not required because + // ~ConstructorTracker() handles that automatically when a leak is found } TEST(ConstructorTrackerTest, DestroyedTwice) { @@ -825,4 +889,5 @@ TEST(ThrowingAllocatorTraitsTest, Assignablility) { } } // namespace -} // namespace absl + +} // namespace testing diff --git a/third_party/abseil-cpp/absl/base/internal/atomic_hook.h b/third_party/abseil-cpp/absl/base/internal/atomic_hook.h index 47d4013928..b458511b0c 100644 --- a/third_party/abseil-cpp/absl/base/internal/atomic_hook.h +++ b/third_party/abseil-cpp/absl/base/internal/atomic_hook.h @@ -21,6 +21,12 @@ #include #include +#ifdef _MSC_FULL_VER +#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0 +#else +#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1 +#endif + namespace absl { namespace base_internal { @@ -29,9 +35,15 @@ class AtomicHook; // AtomicHook is a helper class, templatized on a raw function pointer type, for // implementing Abseil customization hooks. It is a callable object that -// dispatches to the registered hook, or performs a no-op (and returns a default +// dispatches to the registered hook. +// +// A default constructed object performs a no-op (and returns a default // constructed object) if no hook has been registered. // +// Hooks can be pre-registered via constant initialization, for example, +// ABSL_CONST_INIT static AtomicHook my_hook(DefaultAction); +// and then changed at runtime via a call to Store(). +// // Reads and writes guarantee memory_order_acquire/memory_order_release // semantics. template @@ -39,7 +51,19 @@ class AtomicHook { public: using FnPtr = ReturnType (*)(Args...); - constexpr AtomicHook() : hook_(kInitialValue) {} + // Constructs an object that by default performs a no-op (and + // returns a default constructed object) when no hook as been registered. + constexpr AtomicHook() : AtomicHook(DummyFunction) {} + + // Constructs an object that by default dispatches to/returns the + // pre-registered default_fn when no hook has been registered at runtime. +#if ABSL_HAVE_WORKING_ATOMIC_POINTER + explicit constexpr AtomicHook(FnPtr default_fn) + : hook_(default_fn), default_fn_(default_fn) {} +#else + explicit constexpr AtomicHook(FnPtr default_fn) + : hook_(kUninitialized), default_fn_(default_fn) {} +#endif // Stores the provided function pointer as the value for this hook. // @@ -86,16 +110,7 @@ class AtomicHook { // // This causes an issue when building with LLVM under Windows. To avoid this, // we use a less-efficient, intptr_t-based implementation on Windows. - -#ifdef _MSC_FULL_VER -#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0 -#else -#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1 -#endif - #if ABSL_HAVE_WORKING_ATOMIC_POINTER - static constexpr FnPtr kInitialValue = &DummyFunction; - // Return the stored value, or DummyFunction if no value has been stored. FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); } @@ -103,10 +118,9 @@ class AtomicHook { // stored to this object. bool DoStore(FnPtr fn) { assert(fn); - FnPtr expected = DummyFunction; - hook_.compare_exchange_strong(expected, fn, std::memory_order_acq_rel, - std::memory_order_acquire); - const bool store_succeeded = (expected == DummyFunction); + FnPtr expected = default_fn_; + const bool store_succeeded = hook_.compare_exchange_strong( + expected, fn, std::memory_order_acq_rel, std::memory_order_acquire); const bool same_value_already_stored = (expected == fn); return store_succeeded || same_value_already_stored; } @@ -114,15 +128,15 @@ class AtomicHook { std::atomic hook_; #else // !ABSL_HAVE_WORKING_ATOMIC_POINTER // Use a sentinel value unlikely to be the address of an actual function. - static constexpr intptr_t kInitialValue = 0; + static constexpr intptr_t kUninitialized = 0; static_assert(sizeof(intptr_t) >= sizeof(FnPtr), "intptr_t can't contain a function pointer"); FnPtr DoLoad() const { const intptr_t value = hook_.load(std::memory_order_acquire); - if (value == 0) { - return DummyFunction; + if (value == kUninitialized) { + return default_fn_; } return reinterpret_cast(value); } @@ -130,16 +144,17 @@ class AtomicHook { bool DoStore(FnPtr fn) { assert(fn); const auto value = reinterpret_cast(fn); - intptr_t expected = 0; - hook_.compare_exchange_strong(expected, value, std::memory_order_acq_rel, - std::memory_order_acquire); - const bool store_succeeded = (expected == 0); + intptr_t expected = kUninitialized; + const bool store_succeeded = hook_.compare_exchange_strong( + expected, value, std::memory_order_acq_rel, std::memory_order_acquire); const bool same_value_already_stored = (expected == value); return store_succeeded || same_value_already_stored; } std::atomic hook_; #endif + + const FnPtr default_fn_; }; #undef ABSL_HAVE_WORKING_ATOMIC_POINTER diff --git a/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc b/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc new file mode 100644 index 0000000000..cf7407573a --- /dev/null +++ b/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc @@ -0,0 +1,70 @@ +// Copyright 2018 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 +// +// http://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/base/internal/atomic_hook.h" + +#include "gtest/gtest.h" +#include "absl/base/attributes.h" + +namespace { + +int value = 0; +void TestHook(int x) { value = x; } + +TEST(AtomicHookTest, NoDefaultFunction) { + ABSL_CONST_INIT static absl::base_internal::AtomicHook hook; + value = 0; + + // Test the default DummyFunction. + EXPECT_TRUE(hook.Load() == nullptr); + EXPECT_EQ(value, 0); + hook(1); + EXPECT_EQ(value, 0); + + // Test a stored hook. + hook.Store(TestHook); + EXPECT_TRUE(hook.Load() == TestHook); + EXPECT_EQ(value, 0); + hook(1); + EXPECT_EQ(value, 1); + + // Calling Store() with the same hook should not crash. + hook.Store(TestHook); + EXPECT_TRUE(hook.Load() == TestHook); + EXPECT_EQ(value, 1); + hook(2); + EXPECT_EQ(value, 2); +} + +TEST(AtomicHookTest, WithDefaultFunction) { + // Set the default value to TestHook at compile-time. + ABSL_CONST_INIT static absl::base_internal::AtomicHook hook( + TestHook); + value = 0; + + // Test the default value is TestHook. + EXPECT_TRUE(hook.Load() == TestHook); + EXPECT_EQ(value, 0); + hook(1); + EXPECT_EQ(value, 1); + + // Calling Store() with the same hook should not crash. + hook.Store(TestHook); + EXPECT_TRUE(hook.Load() == TestHook); + EXPECT_EQ(value, 1); + hook(2); + EXPECT_EQ(value, 2); +} + +} // namespace diff --git a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h index 4bd273ed7e..2fe345fc85 100644 --- a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h +++ b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h @@ -52,7 +52,7 @@ // SYS_mmap and SYS_munmap are not defined in Android. #ifdef __BIONIC__ -extern "C" void* __mmap2(void*, size_t, int, int, int, long); +extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); #if defined(__NR_mmap) && !defined(SYS_mmap) #define SYS_mmap __NR_mmap #endif diff --git a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc index c6f7c7cfff..d3e94074b8 100644 --- a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc +++ b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc @@ -17,9 +17,14 @@ #include "gtest/gtest.h" #include "absl/meta/type_traits.h" -namespace absl { +namespace testing { -exceptions_internal::NoThrowTag no_throw_ctor; +exceptions_internal::NoThrowTag nothrow_ctor; + +bool nothrow_guarantee(const void*) { + return ::testing::AssertionFailure() + << "Exception thrown violating NoThrow Guarantee"; +} exceptions_internal::StrongGuaranteeTagType strong_guarantee; namespace exceptions_internal { @@ -37,5 +42,7 @@ testing::AssertionResult FailureMessage(const TestException& e, int countdown) noexcept { return testing::AssertionFailure() << "Exception thrown from " << e.what(); } + } // namespace exceptions_internal -} // namespace absl + +} // namespace testing diff --git a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h index 48a292b3e1..c3ff34c50a 100644 --- a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h +++ b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h @@ -35,40 +35,36 @@ #include "absl/strings/substitute.h" #include "absl/types/optional.h" -namespace absl { +namespace testing { -struct ConstructorTracker; +enum class TypeSpec; +enum class AllocSpec; -// A configuration enum for Throwing*. Operations whose flags are set will -// throw, everything else won't. This isn't meant to be exhaustive, more flags -// can always be made in the future. -enum class NoThrow : uint8_t { - kNone = 0, - kMoveCtor = 1, - kMoveAssign = 1 << 1, - kAllocation = 1 << 2, - kIntCtor = 1 << 3, - kNoThrow = static_cast(-1) -}; - -constexpr NoThrow operator|(NoThrow a, NoThrow b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) | static_cast(b)); +constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); } -constexpr NoThrow operator&(NoThrow a, NoThrow b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) & static_cast(b)); +constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) & static_cast(b)); +} + +constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); +} + +constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) & static_cast(b)); } namespace exceptions_internal { + struct NoThrowTag {}; struct StrongGuaranteeTagType {}; -constexpr bool ThrowingAllowed(NoThrow flags, NoThrow flag) { - return !static_cast(flags & flag); -} - // A simple exception class. We throw this so that test code can catch // exceptions specifically thrown by ThrowingValue. class TestException { @@ -105,6 +101,8 @@ void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false); testing::AssertionResult FailureMessage(const TestException& e, int countdown) noexcept; +class ConstructorTracker; + class TrackedObject { public: TrackedObject(const TrackedObject&) = delete; @@ -112,31 +110,61 @@ class TrackedObject { protected: explicit TrackedObject(const char* child_ctor) { - if (!GetAllocs().emplace(this, child_ctor).second) { + if (!GetInstanceMap().emplace(this, child_ctor).second) { ADD_FAILURE() << "Object at address " << static_cast(this) << " re-constructed in ctor " << child_ctor; } } - static std::unordered_map& GetAllocs() { - static auto* m = - new std::unordered_map(); - return *m; - } - ~TrackedObject() noexcept { - if (GetAllocs().erase(this) == 0) { + if (GetInstanceMap().erase(this) == 0) { ADD_FAILURE() << "Object at address " << static_cast(this) << " destroyed improperly"; } } - friend struct ::absl::ConstructorTracker; + private: + using InstanceMap = std::unordered_map; + static InstanceMap& GetInstanceMap() { + static auto* instance_map = new InstanceMap(); + return *instance_map; + } + + friend class ConstructorTracker; +}; + +// Inspects the constructions and destructions of anything inheriting from +// TrackedObject. This allows us to safely "leak" TrackedObjects, as +// ConstructorTracker will destroy everything left over in its destructor. +class ConstructorTracker { + public: + explicit ConstructorTracker(int c) + : init_count_(c), init_instances_(TrackedObject::GetInstanceMap()) {} + ~ConstructorTracker() { + auto& cur_instances = TrackedObject::GetInstanceMap(); + for (auto it = cur_instances.begin(); it != cur_instances.end();) { + if (init_instances_.count(it->first) == 0) { + ADD_FAILURE() << "Object at address " << static_cast(it->first) + << " constructed from " << it->second + << " where the exception countdown was set to " + << init_count_ << " was not destroyed"; + // Erasing an item inside an unordered_map invalidates the existing + // iterator. A new one is returned for iteration to continue. + it = cur_instances.erase(it); + } else { + ++it; + } + } + } + + private: + int init_count_; + TrackedObject::InstanceMap init_instances_; }; template absl::optional TestSingleInvariantAtCountdownImpl( - const Factory& factory, const Operation& operation, int count, + const Factory& factory, Operation operation, int count, const Invariant& invariant) { auto t_ptr = factory(); absl::optional current_res; @@ -199,7 +227,9 @@ inline absl::optional TestAllInvariantsAtCountdown( } // namespace exceptions_internal -extern exceptions_internal::NoThrowTag no_throw_ctor; +extern exceptions_internal::NoThrowTag nothrow_ctor; + +bool nothrow_guarantee(const void*); extern exceptions_internal::StrongGuaranteeTagType strong_guarantee; // A test class which is convertible to bool. The conversion can be @@ -216,47 +246,71 @@ class ThrowingBool { bool b_; }; -// A testing class instrumented to throw an exception at a controlled time. -// -// ThrowingValue implements a slightly relaxed version of the Regular concept -- -// that is it's a value type with the expected semantics. It also implements -// arithmetic operations. It doesn't implement member and pointer operators -// like operator-> or operator[]. -// -// ThrowingValue can be instrumented to have certain operations be noexcept by -// using compile-time bitfield flag template arguments. That is, to make an -// ThrowingValue which has a noexcept move constructor and noexcept move -// assignment, use -// ThrowingValue. -template +/* + * Configuration enum for the ThrowingValue type that defines behavior for the + * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer + * constructor from throwing. + * + * kEverythingThrows: Every operation can throw an exception + * kNoThrowCopy: Copy construction and copy assignment will not throw + * kNoThrowMove: Move construction and move assignment will not throw + * kNoThrowNew: Overloaded operators new and new[] will not throw + */ +enum class TypeSpec { + kEverythingThrows = 0, + kNoThrowCopy = 1, + kNoThrowMove = 1 << 1, + kNoThrowNew = 1 << 2, +}; + +/* + * A testing class instrumented to throw an exception at a controlled time. + * + * ThrowingValue implements a slightly relaxed version of the Regular concept -- + * that is it's a value type with the expected semantics. It also implements + * arithmetic operations. It doesn't implement member and pointer operators + * like operator-> or operator[]. + * + * ThrowingValue can be instrumented to have certain operations be noexcept by + * using compile-time bitfield template arguments. That is, to make an + * ThrowingValue which has noexcept move construction/assignment and noexcept + * copy construction/assignment, use the following: + * ThrowingValue my_thrwr{val}; + */ +template class ThrowingValue : private exceptions_internal::TrackedObject { + static constexpr bool IsSpecified(TypeSpec spec) { + return static_cast(Spec & spec); + } + + static constexpr int kBadValue = 938550620; + public: ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); dummy_ = 0; } - ThrowingValue(const ThrowingValue& other) + ThrowingValue(const ThrowingValue& other) noexcept( + IsSpecified(TypeSpec::kNoThrowCopy)) : TrackedObject(ABSL_PRETTY_FUNCTION) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + if (!IsSpecified(TypeSpec::kNoThrowCopy)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + } dummy_ = other.dummy_; } ThrowingValue(ThrowingValue&& other) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) + IsSpecified(TypeSpec::kNoThrowMove)) : TrackedObject(ABSL_PRETTY_FUNCTION) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) { + if (!IsSpecified(TypeSpec::kNoThrowMove)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); } dummy_ = other.dummy_; } - explicit ThrowingValue(int i) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) - : TrackedObject(ABSL_PRETTY_FUNCTION) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } + explicit ThrowingValue(int i) : TrackedObject(ABSL_PRETTY_FUNCTION) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); dummy_ = i; } @@ -266,15 +320,20 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // absl expects nothrow destructors ~ThrowingValue() noexcept = default; - ThrowingValue& operator=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + ThrowingValue& operator=(const ThrowingValue& other) noexcept( + IsSpecified(TypeSpec::kNoThrowCopy)) { + dummy_ = kBadValue; + if (!IsSpecified(TypeSpec::kNoThrowCopy)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + } dummy_ = other.dummy_; return *this; } ThrowingValue& operator=(ThrowingValue&& other) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) { + IsSpecified(TypeSpec::kNoThrowMove)) { + dummy_ = kBadValue; + if (!IsSpecified(TypeSpec::kNoThrowMove)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); } dummy_ = other.dummy_; @@ -284,22 +343,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Arithmetic Operators ThrowingValue operator+(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ + other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor); } ThrowingValue operator+() const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_, no_throw_ctor); + return ThrowingValue(dummy_, nothrow_ctor); } ThrowingValue operator-(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ - other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor); } ThrowingValue operator-() const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(-dummy_, no_throw_ctor); + return ThrowingValue(-dummy_, nothrow_ctor); } ThrowingValue& operator++() { @@ -310,7 +369,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject { ThrowingValue operator++(int) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - auto out = ThrowingValue(dummy_, no_throw_ctor); + auto out = ThrowingValue(dummy_, nothrow_ctor); ++dummy_; return out; } @@ -323,34 +382,34 @@ class ThrowingValue : private exceptions_internal::TrackedObject { ThrowingValue operator--(int) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - auto out = ThrowingValue(dummy_, no_throw_ctor); + auto out = ThrowingValue(dummy_, nothrow_ctor); --dummy_; return out; } ThrowingValue operator*(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ * other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor); } ThrowingValue operator/(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ / other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor); } ThrowingValue operator%(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ % other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor); } ThrowingValue operator<<(int shift) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ << shift, no_throw_ctor); + return ThrowingValue(dummy_ << shift, nothrow_ctor); } ThrowingValue operator>>(int shift) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ >> shift, no_throw_ctor); + return ThrowingValue(dummy_ >> shift, nothrow_ctor); } // Comparison Operators @@ -406,22 +465,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Bitwise Logical Operators ThrowingValue operator~() const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(~dummy_, no_throw_ctor); + return ThrowingValue(~dummy_, nothrow_ctor); } ThrowingValue operator&(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ & other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor); } ThrowingValue operator|(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ | other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor); } ThrowingValue operator^(const ThrowingValue& other) const { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ ^ other.dummy_, no_throw_ctor); + return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor); } // Compound Assignment operators @@ -503,8 +562,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Args.. allows us to overload regular and placement new in one shot template static void* operator new(size_t s, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); } return ::operator new(s, std::forward(args)...); @@ -512,8 +571,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { template static void* operator new[](size_t s, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); } return ::operator new[](s, std::forward(args)...); @@ -551,20 +610,35 @@ class ThrowingValue : private exceptions_internal::TrackedObject { }; // While not having to do with exceptions, explicitly delete comma operator, to // make sure we don't use it on user-supplied types. -template -void operator,(const ThrowingValue& ef, T&& t) = delete; -template -void operator,(T&& t, const ThrowingValue& ef) = delete; +template +void operator,(const ThrowingValue&, T&&) = delete; +template +void operator,(T&&, const ThrowingValue&) = delete; -// An allocator type which is instrumented to throw at a controlled time, or not -// to throw, using NoThrow. The supported settings are the default of every -// function which is allowed to throw in a conforming allocator possibly -// throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS -// configuration macro. -template +/* + * Configuration enum for the ThrowingAllocator type that defines behavior for + * the lifetime of the instance. + * + * kEverythingThrows: Calls to the member functions may throw + * kNoThrowAllocate: Calls to the member functions will not throw + */ +enum class AllocSpec { + kEverythingThrows = 0, + kNoThrowAllocate = 1, +}; + +/* + * An allocator type which is instrumented to throw at a controlled time, or not + * to throw, using AllocSpec. The supported settings are the default of every + * function which is allowed to throw in a conforming allocator possibly + * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS + * configuration macro. + */ +template class ThrowingAllocator : private exceptions_internal::TrackedObject { - static_assert(Flags == NoThrow::kNone || Flags == NoThrow::kNoThrow, - "Invalid flag"); + static constexpr bool IsSpecified(AllocSpec spec) { + return static_cast(Spec & spec); + } public: using pointer = T*; @@ -577,7 +651,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { using size_type = size_t; using difference_type = ptrdiff_t; - using is_nothrow = std::integral_constant; + using is_nothrow = + std::integral_constant; using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_swap = std::true_type; @@ -589,8 +664,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } template - ThrowingAllocator( // NOLINT - const ThrowingAllocator& other) noexcept + ThrowingAllocator(const ThrowingAllocator& other) noexcept // NOLINT : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {} // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of @@ -599,8 +673,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {} template - ThrowingAllocator( // NOLINT - ThrowingAllocator&& other) noexcept + ThrowingAllocator(ThrowingAllocator&& other) noexcept // NOLINT : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {} ThrowingAllocator(ThrowingAllocator&& other) noexcept @@ -615,29 +688,30 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { template ThrowingAllocator& operator=( - const ThrowingAllocator& other) noexcept { + const ThrowingAllocator& other) noexcept { dummy_ = other.State(); return *this; } template - ThrowingAllocator& operator=(ThrowingAllocator&& other) noexcept { + ThrowingAllocator& operator=(ThrowingAllocator&& other) noexcept { dummy_ = std::move(other.State()); return *this; } template struct rebind { - using other = ThrowingAllocator; + using other = ThrowingAllocator; }; pointer allocate(size_type n) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); return static_cast(::operator new(n * sizeof(T))); } + pointer allocate(size_type n, const_void_pointer) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { return allocate(n); } @@ -648,7 +722,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { template void construct(U* ptr, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); ::new (static_cast(ptr)) U(std::forward(args)...); } @@ -664,23 +738,23 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } ThrowingAllocator select_on_container_copy_construction() noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { auto& out = *this; ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); return out; } template - bool operator==(const ThrowingAllocator& other) const noexcept { + bool operator==(const ThrowingAllocator& other) const noexcept { return dummy_ == other.dummy_; } template - bool operator!=(const ThrowingAllocator& other) const noexcept { + bool operator!=(const ThrowingAllocator& other) const noexcept { return dummy_ != other.dummy_; } - template + template friend class ThrowingAllocator; private: @@ -694,7 +768,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } void ReadStateAndMaybeThrow(absl::string_view msg) const { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + if (!IsSpecified(AllocSpec::kNoThrowAllocate)) { exceptions_internal::MaybeThrow( absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg)); } @@ -704,40 +778,24 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { std::shared_ptr dummy_; }; -template -int ThrowingAllocator::next_id_ = 0; - -// Inspects the constructions and destructions of anything inheriting from -// TrackedObject. Place this as a member variable in a test fixture to ensure -// that every ThrowingValue was constructed and destroyed correctly. This also -// allows us to safely "leak" TrackedObjects, as ConstructorTracker will destroy -// everything left over in its destructor. -struct ConstructorTracker { - ConstructorTracker() = default; - ~ConstructorTracker() { - auto& allocs = exceptions_internal::TrackedObject::GetAllocs(); - for (const auto& kv : allocs) { - ADD_FAILURE() << "Object at address " << static_cast(kv.first) - << " constructed from " << kv.second << " not destroyed"; - } - allocs.clear(); - } -}; +template +int ThrowingAllocator::next_id_ = 0; // Tests for resource leaks by attempting to construct a T using args repeatedly // until successful, using the countdown method. Side effects can then be -// tested for resource leaks. If a ConstructorTracker is present in the test -// fixture, then this will also test that memory resources are not leaked as -// long as T allocates TrackedObjects. +// tested for resource leaks. template -T TestThrowingCtor(Args&&... args) { +void TestThrowingCtor(Args&&... args) { struct Cleanup { ~Cleanup() { exceptions_internal::UnsetCountdown(); } } c; for (int count = 0;; ++count) { + exceptions_internal::ConstructorTracker ct(count); exceptions_internal::SetCountdown(count); try { - return T(std::forward(args)...); + T temp(std::forward(args)...); + static_cast(temp); + break; } catch (const exceptions_internal::TestException&) { } } @@ -859,7 +917,7 @@ class ExceptionSafetyTester { * created in order to get an empty Invariants... list. * * In addition to passing in custom invariant assertion callbacks, this method - * accepts `absl::strong_guarantee` as an argument which checks T instances + * accepts `testing::strong_guarantee` as an argument which checks T instances * post-throw against freshly created T instances via operator== to verify * that any state changes made during the execution of the operation were * properly rolled back. @@ -920,7 +978,7 @@ class ExceptionSafetyTester { template friend class ExceptionSafetyTester; - friend ExceptionSafetyTester<> absl::MakeExceptionSafetyTester(); + friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester(); ExceptionSafetyTester() {} @@ -934,6 +992,8 @@ class ExceptionSafetyTester { // Starting from 0 and counting upwards until one of the exit conditions is // hit... for (int count = 0;; ++count) { + exceptions_internal::ConstructorTracker ct(count); + // Run the full exception safety test algorithm for the current countdown auto reduced_res = TestAllInvariantsAtCountdown(factory_, selected_operation, count, @@ -976,6 +1036,6 @@ MakeExceptionSafetyTester() { return {}; } -} // namespace absl +} // namespace testing #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ diff --git a/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc b/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc new file mode 100644 index 0000000000..fe22e4cff1 --- /dev/null +++ b/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc @@ -0,0 +1,40 @@ +// Copyright 2017 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 +// +// http://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 "benchmark/benchmark.h" +#include "absl/base/internal/thread_identity.h" +#include "absl/synchronization/internal/create_thread_identity.h" +#include "absl/synchronization/internal/per_thread_sem.h" + +namespace { + +void BM_SafeCurrentThreadIdentity(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize( + absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()); + } +} +BENCHMARK(BM_SafeCurrentThreadIdentity); + +void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize( + absl::base_internal::CurrentThreadIdentityIfPresent()); + } +} +BENCHMARK(BM_UnsafeCurrentThreadIdentity); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/third_party/abseil-cpp/absl/base/macros.h b/third_party/abseil-cpp/absl/base/macros.h index 114a7be131..afa30300bc 100644 --- a/third_party/abseil-cpp/absl/base/macros.h +++ b/third_party/abseil-cpp/absl/base/macros.h @@ -36,21 +36,20 @@ // ABSL_ARRAYSIZE() // -// Returns the # of elements in an array as a compile-time constant, which can -// be used in defining new arrays. If you use this macro on a pointer by +// Returns the number of elements in an array as a compile-time constant, which +// can be used in defining new arrays. If you use this macro on a pointer by // mistake, you will get a compile-time error. -// -// Note: this template function declaration is used in defining arraysize. -// Note that the function doesn't need an implementation, as we only -// use its type. +#define ABSL_ARRAYSIZE(array) \ + (sizeof(::absl::macros_internal::ArraySizeHelper(array))) + namespace absl { namespace macros_internal { +// Note: this internal template function declaration is used by ABSL_ARRAYSIZE. +// The function doesn't need a definition, as we only use its type. template auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; } // namespace macros_internal } // namespace absl -#define ABSL_ARRAYSIZE(array) \ - (sizeof(::absl::macros_internal::ArraySizeHelper(array))) // kLinkerInitialized // diff --git a/third_party/abseil-cpp/absl/base/policy_checks.h b/third_party/abseil-cpp/absl/base/policy_checks.h index d634dac68d..0a07fc035e 100644 --- a/third_party/abseil-cpp/absl/base/policy_checks.h +++ b/third_party/abseil-cpp/absl/base/policy_checks.h @@ -86,7 +86,7 @@ // in May, 2010 and includes some functionality used in Google software // (for instance pthread_setname_np): // https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html -#ifdef __GLIBC_PREREQ +#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) #if !__GLIBC_PREREQ(2, 12) #error "Minimum required version of glibc is 2.12." #endif diff --git a/third_party/abseil-cpp/absl/container/BUILD.bazel b/third_party/abseil-cpp/absl/container/BUILD.bazel index 8bdf63122a..303410834b 100644 --- a/third_party/abseil-cpp/absl/container/BUILD.bazel +++ b/third_party/abseil-cpp/absl/container/BUILD.bazel @@ -62,6 +62,17 @@ cc_test( ], ) +cc_test( + name = "fixed_array_benchmark", + srcs = ["fixed_array_benchmark.cc"], + copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"], + tags = ["benchmark"], + deps = [ + ":fixed_array", + "@com_github_google_benchmark//:benchmark", + ], +) + cc_library( name = "inlined_vector", hdrs = ["inlined_vector.h"], @@ -106,6 +117,19 @@ cc_test( ], ) +cc_test( + name = "inlined_vector_benchmark", + srcs = ["inlined_vector_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + deps = [ + ":inlined_vector", + "//absl/base", + "//absl/strings", + "@com_github_google_benchmark//:benchmark", + ], +) + cc_library( name = "test_instance_tracker", testonly = 1, diff --git a/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc b/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc new file mode 100644 index 0000000000..2d39898d8a --- /dev/null +++ b/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc @@ -0,0 +1,68 @@ +// Copyright 2017 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 +// +// http://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/container/fixed_array.h" + +#include +#include + +#include "benchmark/benchmark.h" + +namespace { + +// For benchmarking -- simple class with constructor and destructor that +// set an int to a constant.. +class SimpleClass { + public: + SimpleClass() : i(3) { } + ~SimpleClass() { i = 0; } + private: + int i; +}; + +template +void BM_FixedArray(benchmark::State& state) { + const int size = state.range(0); + for (auto _ : state) { + absl::FixedArray fa(size); + benchmark::DoNotOptimize(fa.data()); + } +} +BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault) + ->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16); + +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault) + ->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16); + +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault) + ->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16); +BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc new file mode 100644 index 0000000000..c6bc5cd96d --- /dev/null +++ b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc @@ -0,0 +1,376 @@ +// Copyright 2017 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 +// +// http://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/container/inlined_vector.h" + +#include +#include + +#include "benchmark/benchmark.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/strings/str_cat.h" + +namespace { + +using IntVec = absl::InlinedVector; + +void BM_InlinedVectorFill(benchmark::State& state) { + const int len = state.range(0); + for (auto _ : state) { + IntVec v; + for (int i = 0; i < len; i++) { + v.push_back(i); + } + } + state.SetItemsProcessed(static_cast(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); + +void BM_InlinedVectorFillRange(benchmark::State& state) { + const int len = state.range(0); + std::unique_ptr ia(new int[len]); + for (int i = 0; i < len; i++) { + ia[i] = i; + } + for (auto _ : state) { + IntVec v(ia.get(), ia.get() + len); + benchmark::DoNotOptimize(v); + } + state.SetItemsProcessed(static_cast(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); + +void BM_StdVectorFill(benchmark::State& state) { + const int len = state.range(0); + for (auto _ : state) { + std::vector v; + for (int i = 0; i < len; i++) { + v.push_back(i); + } + } + state.SetItemsProcessed(static_cast(state.iterations()) * len); +} +BENCHMARK(BM_StdVectorFill)->Range(0, 1024); + +bool StringRepresentedInline(std::string s) { + const char* chars = s.data(); + std::string s1 = std::move(s); + return s1.data() != chars; +} + +void BM_InlinedVectorFillString(benchmark::State& state) { + const int len = state.range(0); + std::string strings[4] = {"a quite long string", + "another long string", + "012345678901234567", + "to cause allocation"}; + for (auto _ : state) { + absl::InlinedVector v; + for (int i = 0; i < len; i++) { + v.push_back(strings[i & 3]); + } + } + state.SetItemsProcessed(static_cast(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); + +void BM_StdVectorFillString(benchmark::State& state) { + const int len = state.range(0); + std::string strings[4] = {"a quite long string", + "another long string", + "012345678901234567", + "to cause allocation"}; + for (auto _ : state) { + std::vector v; + for (int i = 0; i < len; i++) { + v.push_back(strings[i & 3]); + } + } + state.SetItemsProcessed(static_cast(state.iterations()) * len); + // The purpose of the benchmark is to verify that inlined vector is + // efficient when moving is more efficent than copying. To do so, we + // use strings that are larger than the small std::string optimization. + ABSL_RAW_CHECK(!StringRepresentedInline(strings[0]), + "benchmarked with strings that are too small"); +} +BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); + +struct Buffer { // some arbitrary structure for benchmarking. + char* base; + int length; + int capacity; + void* user_data; +}; + +void BM_InlinedVectorTenAssignments(benchmark::State& state) { + const int len = state.range(0); + using BufferVec = absl::InlinedVector; + + BufferVec src; + src.resize(len); + + BufferVec dst; + for (auto _ : state) { + for (int i = 0; i < 10; ++i) { + dst = src; + } + } +} +BENCHMARK(BM_InlinedVectorTenAssignments) + ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); + +void BM_CreateFromContainer(benchmark::State& state) { + for (auto _ : state) { + absl::InlinedVector x(absl::InlinedVector{1, 2, 3}); + benchmark::DoNotOptimize(x); + } +} +BENCHMARK(BM_CreateFromContainer); + +struct LargeCopyableOnly { + LargeCopyableOnly() : d(1024, 17) {} + LargeCopyableOnly(const LargeCopyableOnly& o) = default; + LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default; + + std::vector d; +}; + +struct LargeCopyableSwappable { + LargeCopyableSwappable() : d(1024, 17) {} + LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; + LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete; + + LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { + using std::swap; + swap(*this, o); + return *this; + } + LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete; + + friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { + using std::swap; + swap(a.d, b.d); + } + + std::vector d; +}; + +struct LargeCopyableMovable { + LargeCopyableMovable() : d(1024, 17) {} + // Use implicitly defined copy and move. + + std::vector d; +}; + +struct LargeCopyableMovableSwappable { + LargeCopyableMovableSwappable() : d(1024, 17) {} + LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) = + default; + LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default; + + LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) { + using std::swap; + swap(*this, o); + return *this; + } + LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) = + default; + + friend void swap(LargeCopyableMovableSwappable& a, + LargeCopyableMovableSwappable& b) { + using std::swap; + swap(a.d, b.d); + } + + std::vector d; +}; + +template +void BM_SwapElements(benchmark::State& state) { + const int len = state.range(0); + using Vec = absl::InlinedVector; + Vec a(len); + Vec b; + for (auto _ : state) { + using std::swap; + swap(a, b); + } +} +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable) + ->Range(0, 1024); + +// The following benchmark is meant to track the efficiency of the vector size +// as a function of stored type via the benchmark label. It is not meant to +// output useful sizeof operator performance. The loop is a dummy operation +// to fulfill the requirement of running the benchmark. +template +void BM_Sizeof(benchmark::State& state) { + int size = 0; + for (auto _ : state) { + VecType vec; + size = sizeof(vec); + } + state.SetLabel(absl::StrCat("sz=", size)); +} +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); + +void BM_InlinedVectorIndexInlined(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorIndexInlined); + +void BM_InlinedVectorIndexExternal(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorIndexExternal); + +void BM_StdVectorIndex(benchmark::State& state) { + std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast(state.iterations())); +} +BENCHMARK(BM_StdVectorIndex); + +#define UNROLL_2(x) \ + benchmark::DoNotOptimize(x); \ + benchmark::DoNotOptimize(x); + +#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x) +#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x) +#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x); + +void BM_InlinedVectorDataInlined(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorDataInlined); + +void BM_InlinedVectorDataExternal(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorDataExternal); + +void BM_StdVectorData(benchmark::State& state) { + std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_StdVectorData); + +void BM_InlinedVectorSizeInlined(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorSizeInlined); + +void BM_InlinedVectorSizeExternal(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorSizeExternal); + +void BM_StdVectorSize(benchmark::State& state) { + std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_StdVectorSize); + +void BM_InlinedVectorEmptyInlined(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorEmptyInlined); + +void BM_InlinedVectorEmptyExternal(benchmark::State& state) { + absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_InlinedVectorEmptyExternal); + +void BM_StdVectorEmpty(benchmark::State& state) { + std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast(state.iterations())); +} +BENCHMARK(BM_StdVectorEmpty); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/third_party/abseil-cpp/absl/debugging/BUILD.bazel index 8543200df8..e1e7fced69 100644 --- a/third_party/abseil-cpp/absl/debugging/BUILD.bazel +++ b/third_party/abseil-cpp/absl/debugging/BUILD.bazel @@ -46,6 +46,7 @@ cc_library( "symbolize.cc", "symbolize_elf.inc", "symbolize_unimplemented.inc", + "symbolize_win32.inc", ], hdrs = [ "internal/symbolize.h", @@ -93,6 +94,38 @@ cc_library( ], ) +cc_library( + name = "failure_signal_handler", + srcs = ["failure_signal_handler.cc"], + hdrs = ["failure_signal_handler.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + ":examine_stack", + ":stacktrace", + "//absl/base", + "//absl/base:config", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "failure_signal_handler_test", + srcs = ["failure_signal_handler_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = select({ + "//absl:windows": [], + "//conditions:default": ["-pthread"], + }), + deps = [ + ":failure_signal_handler", + ":stacktrace", + ":symbolize", + "//absl/base", + "//absl/strings", + "@com_google_googletest//:gtest", + ], +) + cc_library( name = "debugging_internal", srcs = [ diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn index 2838b77e84..18e2f4fe8f 100644 --- a/third_party/abseil-cpp/absl/debugging/BUILD.gn +++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn @@ -46,6 +46,7 @@ source_set("symbolize") { "symbolize.cc", "symbolize_elf.inc", "symbolize_unimplemented.inc", + "symbolize_win32.inc", ] public = [ "internal/symbolize.h", @@ -83,6 +84,28 @@ source_set("examine_stack") { ] } +source_set("failure_signal_handler") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + sources = [ + "failure_signal_handler.cc" + ] + public = [ + "failure_signal_handler.h" + ] + deps = [ + ":examine_stack", + ":stacktrace", + "../base", + "../base:config", + "../base:core_headers", + ] +} + source_set("debugging_internal") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ diff --git a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt index 8d2ec845d6..4af2ec8a41 100644 --- a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt @@ -15,12 +15,14 @@ # list(APPEND DEBUGGING_PUBLIC_HEADERS + "failure_signal_handler.h" "leak_check.h" "stacktrace.h" "symbolize.h" ) - +# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in +# Bazel list(APPEND DEBUGGING_INTERNAL_HEADERS "internal/address_is_readable.h" "internal/demangle.h" @@ -31,12 +33,16 @@ list(APPEND DEBUGGING_INTERNAL_HEADERS "internal/vdso_support.h" ) - -list(APPEND STACKTRACE_SRC - "stacktrace.cc" +list(APPEND DEBUGGING_INTERNAL_SRC "internal/address_is_readable.cc" "internal/elf_mem_image.cc" "internal/vdso_support.cc" +) + + +list(APPEND STACKTRACE_SRC + "stacktrace.cc" + ${DEBUGGING_INTERNAL_SRC} ${DEBUGGING_PUBLIC_HEADERS} ${DEBUGGING_INTERNAL_HEADERS} ) @@ -45,9 +51,16 @@ list(APPEND SYMBOLIZE_SRC "symbolize.cc" "symbolize_elf.inc" "symbolize_unimplemented.inc" + "symbolize_win32.inc" "internal/demangle.cc" ${DEBUGGING_PUBLIC_HEADERS} ${DEBUGGING_INTERNAL_HEADERS} + ${DEBUGGING_INTERNAL_SRC} +) + +list(APPEND FAILURE_SIGNAL_HANDLER_SRC + "failure_signal_handler.cc" + ${DEBUGGING_PUBLIC_HEADERS} ) list(APPEND EXAMINE_STACK_SRC @@ -70,10 +83,24 @@ absl_library( absl_symbolize SOURCES ${SYMBOLIZE_SRC} + PUBLIC_LIBRARIES + absl::base + absl_malloc_internal EXPORT_NAME symbolize ) +absl_library( + TARGET + absl_failure_signal_handler + SOURCES + ${FAILURE_SIGNAL_HANDLER_SRC} + PUBLIC_LIBRARIES + absl_base absl::examine_stack absl::stacktrace absl_synchronization + EXPORT_NAME + failure_signal_handler +) + # Internal-only. Projects external to Abseil should not depend # directly on this library. absl_library( @@ -117,13 +144,9 @@ absl_header_library( ## TESTS # -list(APPEND DEBUGGING_INTERNAL_TEST_HEADERS - "internal/stack_consumption.h" -) - list(APPEND STACK_CONSUMPTION_SRC "internal/stack_consumption.cc" - ${DEBUGGING_INTERNAL_TEST_HEADERS} + "internal/stack_consumption.h" ) absl_library( @@ -137,10 +160,13 @@ absl_test( TARGET absl_stack_consumption_test SOURCES - ${STACK_CONSUMPTION_SRC} + "internal/stack_consumption_test.cc" + PUBLIC_LIBRARIES + absl_stack_consumption + absl::base ) -list(APPEND DEMANGLE_TEST_SRC "demangle_test.cc") +list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc") absl_test( TARGET @@ -159,7 +185,23 @@ absl_test( SOURCES ${SYMBOLIZE_TEST_SRC} PUBLIC_LIBRARIES - absl_symbolize absl_stack_consumption + absl::base absl::memory absl_symbolize absl_stack_consumption +) + +list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc") + +absl_test( + TARGET + failure_signal_handler_test + SOURCES + ${FAILURE_SIGNAL_HANDLER_TEST_SRC} + PUBLIC_LIBRARIES + absl_examine_stack + absl_failure_signal_handler + absl_stacktrace + absl_symbolize + absl::base + absl::strings ) # test leak_check_test diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc new file mode 100644 index 0000000000..46ef7b8f5a --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc @@ -0,0 +1,356 @@ +// +// Copyright 2018 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 +// +// http://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/failure_signal_handler.h" + +#include "absl/base/config.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifdef ABSL_HAVE_MMAP +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/debugging/internal/examine_stack.h" +#include "absl/debugging/stacktrace.h" + +#ifndef _WIN32 +#define ABSL_HAVE_SIGACTION +#endif + +namespace absl { + +ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options; + +// Resets the signal handler for signo to the default action for that +// signal, then raises the signal. +static void RaiseToDefaultHandler(int signo) { + signal(signo, SIG_DFL); + raise(signo); +} + +struct FailureSignalData { + const int signo; + const char* const as_string; +#ifdef ABSL_HAVE_SIGACTION + struct sigaction previous_action; + // StructSigaction is used to silence -Wmissing-field-initializers. + using StructSigaction = struct sigaction; + #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() +#else + void (*previous_handler)(int); + #define FSD_PREVIOUS_INIT SIG_DFL +#endif +}; + +ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = { + {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT}, + {SIGILL, "SIGILL", FSD_PREVIOUS_INIT}, + {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT}, + {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT}, + {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT}, +#ifndef _WIN32 + {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT}, + {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT}, +#endif +}; + +#undef FSD_PREVIOUS_INIT + +static void RaiseToPreviousHandler(int signo) { + // Search for the previous handler. + for (const auto& it : failure_signal_data) { + if (it.signo == signo) { +#ifdef ABSL_HAVE_SIGACTION + sigaction(signo, &it.previous_action, nullptr); +#else + signal(signo, it.previous_handler); +#endif + raise(signo); + return; + } + } + + // Not found, use the default handler. + RaiseToDefaultHandler(signo); +} + +namespace debugging_internal { + +const char* FailureSignalToString(int signo) { + for (const auto& it : failure_signal_data) { + if (it.signo == signo) { + return it.as_string; + } + } + return ""; +} + +} // namespace debugging_internal + +#ifndef _WIN32 + +static bool SetupAlternateStackOnce() { + const size_t page_mask = getpagesize() - 1; + size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; +#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ + defined(THREAD_SANITIZER) + // Account for sanitizer instrumentation requiring additional stack space. + stack_size *= 5; +#endif + + stack_t sigstk; + memset(&sigstk, 0, sizeof(sigstk)); + sigstk.ss_size = stack_size; + +#ifdef ABSL_HAVE_MMAP +#ifndef MAP_STACK +#define MAP_STACK 0 +#endif +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif + sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (sigstk.ss_sp == MAP_FAILED) { + ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed"); + } +#else + sigstk.ss_sp = malloc(sigstk.ss_size); + if (sigstk.ss_sp == nullptr) { + ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed"); + } +#endif + + if (sigaltstack(&sigstk, nullptr) != 0) { + ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno); + } + return true; +} + +#endif + +// Sets up an alternate stack for signal handlers once. +// Returns the appropriate flag for sig_action.sa_flags +// if the system supports using an alternate stack. +static int MaybeSetupAlternateStack() { +#ifndef _WIN32 + ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce(); + return SA_ONSTACK; +#else + return 0; +#endif +} + +#ifdef ABSL_HAVE_SIGACTION + +static void InstallOneFailureHandler(FailureSignalData* data, + void (*handler)(int, siginfo_t*, void*)) { + struct sigaction act; + memset(&act, 0, sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_flags |= SA_SIGINFO; + // SA_NODEFER is required to handle SIGABRT from + // ImmediateAbortSignalHandler(). + act.sa_flags |= SA_NODEFER; + if (fsh_options.use_alternate_stack) { + act.sa_flags |= MaybeSetupAlternateStack(); + } + act.sa_sigaction = handler; + ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0, + "sigaction() failed"); +} + +#else + +static void InstallOneFailureHandler(FailureSignalData* data, + void (*handler)(int)) { + data->previous_handler = signal(data->signo, handler); + ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed"); +} + +#endif + +static void WriteToStderr(const char* data) { + int old_errno = errno; + absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data)); + errno = old_errno; +} + +static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) { + char buf[64]; + const char* const signal_string = + debugging_internal::FailureSignalToString(signo); + if (signal_string != nullptr && signal_string[0] != '\0') { + snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n", + signal_string, + static_cast(time(nullptr))); // NOLINT(runtime/int) + } else { + snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n", + signo, static_cast(time(nullptr))); // NOLINT(runtime/int) + } + writerfn(buf); +} + +// `void*` might not be big enough to store `void(*)(const char*)`. +struct WriterFnStruct { + void (*writerfn)(const char*); +}; + +// Many of the absl::debugging_internal::Dump* functions in +// examine_stack.h take a writer function pointer that has a void* arg +// for historical reasons. failure_signal_handler_writer only takes a +// data pointer. This function converts between these types. +static void WriterFnWrapper(const char* data, void* arg) { + static_cast(arg)->writerfn(data); +} + +// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal +// handlers. "noinline" so that GetStackFrames() skips the top-most stack +// frame for this function. +ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace( + void* ucontext, bool symbolize_stacktrace, + void (*writerfn)(const char*, void*), void* writerfn_arg) { + constexpr int kNumStackFrames = 32; + void* stack[kNumStackFrames]; + int frame_sizes[kNumStackFrames]; + int min_dropped_frames; + int depth = absl::GetStackFramesWithContext( + stack, frame_sizes, kNumStackFrames, + 1, // Do not include this function in stack trace. + ucontext, &min_dropped_frames); + absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace( + absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes, + depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg); +} + +// Called by FailureSignalHandler() to write the failure info. It is +// called once with writerfn set to WriteToStderr() and then possibly +// with writerfn set to the user provided function. +static void WriteFailureInfo(int signo, void* ucontext, + void (*writerfn)(const char*)) { + WriterFnStruct writerfn_struct{writerfn}; + WriteSignalMessage(signo, writerfn); + WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper, + &writerfn_struct); +} + +// absl::SleepFor() can't be used here since AbslInternalSleepFor() +// may be overridden to do something that isn't async-signal-safe on +// some platforms. +static void PortableSleepForSeconds(int seconds) { +#ifdef _WIN32 + Sleep(seconds * 1000); +#else + struct timespec sleep_time; + sleep_time.tv_sec = seconds; + sleep_time.tv_nsec = 0; + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {} +#endif +} + +#ifdef ABSL_HAVE_ALARM +// FailureSignalHandler() installs this as a signal handler for +// SIGALRM, then sets an alarm to be delivered to the program after a +// set amount of time. If FailureSignalHandler() hangs for more than +// the alarm timeout, ImmediateAbortSignalHandler() will abort the +// program. +static void ImmediateAbortSignalHandler(int) { + RaiseToDefaultHandler(SIGABRT); +} +#endif + +// absl::base_internal::GetTID() returns pid_t on most platforms, but +// returns absl::base_internal::pid_t on Windows. +using GetTidType = decltype(absl::base_internal::GetTID()); +ABSL_CONST_INIT static std::atomic failed_tid(0); + +#ifndef ABSL_HAVE_SIGACTION +static void FailureSignalHandler(int signo) { + void* ucontext = nullptr; +#else +static void FailureSignalHandler(int signo, siginfo_t*, + void* ucontext) { +#endif + + const GetTidType this_tid = absl::base_internal::GetTID(); + GetTidType previous_failed_tid = 0; + if (!failed_tid.compare_exchange_strong( + previous_failed_tid, static_cast(this_tid), + std::memory_order_acq_rel, std::memory_order_relaxed)) { + ABSL_RAW_LOG( + ERROR, + "Signal %d raised at PC=%p while already in FailureSignalHandler()", + signo, absl::debugging_internal::GetProgramCounter(ucontext)); + if (this_tid != previous_failed_tid) { + // Another thread is already in FailureSignalHandler(), so wait + // a bit for it to finish. If the other thread doesn't kill us, + // we do so after sleeping. + PortableSleepForSeconds(3); + RaiseToDefaultHandler(signo); + // The recursively raised signal may be blocked until we return. + return; + } + } + +#ifdef ABSL_HAVE_ALARM + // Set an alarm to abort the program in case this code hangs or deadlocks. + if (fsh_options.alarm_on_failure_secs > 0) { + alarm(0); // Cancel any existing alarms. + signal(SIGALRM, ImmediateAbortSignalHandler); + alarm(fsh_options.alarm_on_failure_secs); + } +#endif + + // First write to stderr. + WriteFailureInfo(signo, ucontext, WriteToStderr); + + // Riskier code (because it is less likely to be async-signal-safe) + // goes after this point. + if (fsh_options.writerfn != nullptr) { + WriteFailureInfo(signo, ucontext, fsh_options.writerfn); + } + + if (fsh_options.call_previous_handler) { + RaiseToPreviousHandler(signo); + } else { + RaiseToDefaultHandler(signo); + } +} + +void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) { + fsh_options = options; + for (auto& it : failure_signal_data) { + InstallOneFailureHandler(&it, FailureSignalHandler); + } +} + +} // namespace absl diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h new file mode 100644 index 0000000000..c57954e587 --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h @@ -0,0 +1,117 @@ +// Copyright 2018 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 +// +// http://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. +// +// ----------------------------------------------------------------------------- +// File: failure_signal_handler.h +// ----------------------------------------------------------------------------- +// +// This file configures the Abseil *failure signal handler* to capture and dump +// useful debugging information (such as a stacktrace) upon program failure. +// +// To use the failure signal handler, call `absl::InstallFailureSignalHandler()` +// very early in your program, usually in the first few lines of main(): +// +// int main(int argc, char** argv) { +// // Initialize the symbolizer to get a human-readable stack trace +// absl::InitializeSymbolizer(argv[0]); +// +// absl::FailureSignalHandlerOptions options; +// absl::InstallFailureSignalHandler(options); +// DoSomethingInteresting(); +// return 0; +// } +// +// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`, +// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the +// installed failure signal handler and provide debugging information to stderr. +// +// Note that you should *not* install the Abseil failure signal handler more +// than once. You may, of course, have another (non-Abseil) failure signal +// handler installed (which would be triggered if Abseil's failure signal +// handler sets `call_previous_handler` to `true`). + +#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ +#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ + +namespace absl { + +// FailureSignalHandlerOptions +// +// Struct for holding `absl::InstallFailureSignalHandler()` configuration +// options. +struct FailureSignalHandlerOptions { + // If true, try to symbolize the stacktrace emitted on failure, provided that + // you have initialized a symbolizer for that purpose. (See symbolize.h for + // more information.) + bool symbolize_stacktrace = true; + + // If true, try to run signal handlers on an alternate stack (if supported on + // the given platform). An alternate stack is useful for program crashes due + // to a stack overflow; by running on a alternate stack, the signal handler + // may run even when normal stack space has been exausted. The downside of + // using an alternate stack is that extra memory for the alternate stack needs + // to be pre-allocated. + bool use_alternate_stack = true; + + // If positive, indicates the number of seconds after which the failure signal + // handler is invoked to abort the program. Setting such an alarm is useful in + // cases where the failure signal handler itself may become hung or + // deadlocked. + int alarm_on_failure_secs = 3; + + // If true, call the previously registered signal handler for the signal that + // was received (if one was registered) after the existing signal handler + // runs. This mechanism can be used to chain signal handlers together. + // + // If false, the signal is raised to the default handler for that signal + // (which normally terminates the program). + // + // IMPORTANT: If true, the chained fatal signal handlers must not try to + // recover from the fatal signal. Instead, they should terminate the program + // via some mechanism, like raising the default handler for the signal, or by + // calling `_exit()`. Note that the failure signal handler may put parts of + // the Abseil library into a state from which they cannot recover. + bool call_previous_handler = false; + + // If non-null, indicates a pointer to a callback function that will be called + // upon failure, with a std::string argument containing failure data. This function + // may be used as a hook to write failure data to a secondary location, such + // as a log file. This function may also be called with null data, as a hint + // to flush any buffered data before the program may be terminated. Consider + // flushing any buffered data in all calls to this function. + // + // Since this function runs within a signal handler, it should be + // async-signal-safe if possible. + // See http://man7.org/linux/man-pages/man7/signal-safety.7.html + void (*writerfn)(const char*) = nullptr; +}; + +// InstallFailureSignalHandler() +// +// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`, +// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist +// on the given platform). The failure signal handler dumps program failure data +// useful for debugging in an unspecified format to stderr. This data may +// include the program counter, a stacktrace, and register information on some +// systems; do not rely on an exact format for the output, as it is subject to +// change. +void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options); + +namespace debugging_internal { +const char* FailureSignalToString(int signo); +} // namespace debugging_internal + +} // namespace absl + +#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc new file mode 100644 index 0000000000..ba520910f4 --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc @@ -0,0 +1,155 @@ +// +// Copyright 2018 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 +// +// http://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/failure_signal_handler.h" + +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" + +namespace { + +#if GTEST_HAS_DEATH_TEST + +// For the parameterized death tests. GetParam() returns the signal number. +using FailureSignalHandlerDeathTest = ::testing::TestWithParam; + +// This function runs in a fork()ed process on most systems. +void InstallHandlerAndRaise(int signo) { + absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions()); + raise(signo); +} + +TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) { + const int signo = GetParam(); + std::string exit_regex = absl::StrCat( + "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo), + " received at time="); +#ifndef _WIN32 + EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo), + exit_regex); +#else + // Windows doesn't have testing::KilledBySignal(). + EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex); +#endif +} + +ABSL_CONST_INIT FILE* error_file = nullptr; + +void WriteToErrorFile(const char* msg) { + if (msg != nullptr) { + ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1, + "fwrite() failed"); + } + ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed"); +} + +std::string GetTmpDir() { + // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel. + static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP", + "TEMPDIR", "TMP"}; + for (const char* const var : kTmpEnvVars) { + const char* tmp_dir = std::getenv(var); + if (tmp_dir != nullptr) { + return tmp_dir; + } + } + + // Try something reasonable. + return "/tmp"; +} + +// This function runs in a fork()ed process on most systems. +void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) { + error_file = fopen(file, "w"); + ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file"); + absl::FailureSignalHandlerOptions options; + options.writerfn = WriteToErrorFile; + absl::InstallFailureSignalHandler(options); + raise(signo); +} + +TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) { + const int signo = GetParam(); + std::string tmp_dir = GetTmpDir(); + std::string file = absl::StrCat(tmp_dir, "/signo_", signo); + + std::string exit_regex = absl::StrCat( + "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo), + " received at time="); +#ifndef _WIN32 + EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), + testing::KilledBySignal(signo), exit_regex); +#else + // Windows doesn't have testing::KilledBySignal(). + EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), + exit_regex); +#endif + + // Open the file in this process and check its contents. + std::fstream error_output(file); + ASSERT_TRUE(error_output.is_open()) << file; + std::string error_line; + std::getline(error_output, error_line); + EXPECT_TRUE(absl::StartsWith( + error_line, + absl::StrCat("*** ", + absl::debugging_internal::FailureSignalToString(signo), + " received at "))); + + if (absl::debugging_internal::StackTraceWorksForTest()) { + std::getline(error_output, error_line); + EXPECT_TRUE(absl::StartsWith(error_line, "PC: ")); + } +} + +constexpr int kFailureSignals[] = { + SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM, +#ifndef _WIN32 + SIGBUS, SIGTRAP, +#endif +}; + +std::string SignalParamToString(const ::testing::TestParamInfo& info) { + std::string result = absl::debugging_internal::FailureSignalToString(info.param); + if (result.empty()) { + result = absl::StrCat(info.param); + } + return result; +} + +INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest, + ::testing::ValuesIn(kFailureSignals), + SignalParamToString); + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace + +int main(int argc, char** argv) { + absl::InitializeSymbolizer(argv[0]); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc index d6d5192460..3f747e7f95 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc @@ -121,7 +121,7 @@ const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const { return reinterpret_cast(sym->st_value); } ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range"); - return GetTableElement(ehdr_, 0, 1, sym->st_value) - link_base_; + return GetTableElement(ehdr_, 0, 1, sym->st_value - link_base_); } const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const { @@ -161,10 +161,6 @@ void ElfMemImage::Init(const void *base) { if (!base) { return; } - const intptr_t base_as_uintptr_t = reinterpret_cast(base); - // Fake VDSO has low bit set. - const bool fake_vdso = ((base_as_uintptr_t & 1) != 0); - base = reinterpret_cast(base_as_uintptr_t & ~1); const char *const base_as_char = reinterpret_cast(base); if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { @@ -224,21 +220,7 @@ void ElfMemImage::Init(const void *base) { reinterpret_cast(dynamic_program_header->p_vaddr + relocation); for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { - ElfW(Xword) value = dynamic_entry->d_un.d_val; - if (fake_vdso) { - // A complication: in the real VDSO, dynamic entries are not relocated - // (it wasn't loaded by a dynamic loader). But when testing with a - // "fake" dlopen()ed vdso library, the loader relocates some (but - // not all!) of them before we get here. - if (dynamic_entry->d_tag == DT_VERDEF) { - // The only dynamic entry (of the ones we care about) libc-2.3.6 - // loader doesn't relocate. - value += relocation; - } - } else { - // Real VDSO. Everything needs to be relocated. - value += relocation; - } + const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation; switch (dynamic_entry->d_tag) { case DT_HASH: hash_ = reinterpret_cast(value); diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc index a861c0a182..7ed6b3eb82 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -14,6 +14,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/debugging/internal/address_is_readable.h" #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems #include "absl/debugging/stacktrace.h" @@ -24,7 +25,7 @@ static const uintptr_t kUnknownFrameSize = 0; // Returns the address of the VDSO __kernel_rt_sigreturn function, if present. static const unsigned char* GetKernelRtSigreturnAddress() { constexpr uintptr_t kImpossibleAddress = 1; - static std::atomic memoized{kImpossibleAddress}; + ABSL_CONST_INIT static std::atomic memoized{kImpossibleAddress}; uintptr_t address = memoized.load(std::memory_order_relaxed); if (address != kImpossibleAddress) { return reinterpret_cast(address); diff --git a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h index 7ae13839b7..8d926fec48 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h +++ b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h @@ -20,6 +20,7 @@ #include #include +#include "absl/base/port.h" // Needed for string vs std::string #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set diff --git a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h index 870a60a410..8002c7405f 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h +++ b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h @@ -41,6 +41,7 @@ #include +#include "absl/base/attributes.h" #include "absl/debugging/internal/elf_mem_image.h" #ifdef ABSL_HAVE_ELF_MEM_IMAGE @@ -132,7 +133,7 @@ class VDSOSupport { // This function pointer may point to InitAndGetCPU, // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization. - static std::atomic getcpu_fn_; + ABSL_CONST_INIT static std::atomic getcpu_fn_; friend int GetCPU(void); // Needs access to getcpu_fn_. diff --git a/third_party/abseil-cpp/absl/debugging/leak_check.h b/third_party/abseil-cpp/absl/debugging/leak_check.h index f67fe88a0f..c930684e95 100644 --- a/third_party/abseil-cpp/absl/debugging/leak_check.h +++ b/third_party/abseil-cpp/absl/debugging/leak_check.h @@ -1,5 +1,4 @@ -// -// Copyright 2017 The Abseil Authors. +// Copyright 2018 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. @@ -13,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // - // ----------------------------------------------------------------------------- // File: leak_check.h // ----------------------------------------------------------------------------- // -// This package contains functions that affect leak checking behavior within +// This file contains functions that affect leak checking behavior within // targets built with the LeakSanitizer (LSan), a memory leak detector that is // integrated within the AddressSanitizer (ASan) as an additional component, or -// which can be used standalone. LSan and ASan are included or can be provided +// which can be used standalone. LSan and ASan are included (or can be provided) // as additional components for most compilers such as Clang, gcc and MSVC. // Note: this leak checking API is not yet supported in MSVC. // Leak checking is enabled by default in all ASan builds. diff --git a/third_party/abseil-cpp/absl/debugging/stacktrace.h b/third_party/abseil-cpp/absl/debugging/stacktrace.h index 82da3f15fa..8b831e2681 100644 --- a/third_party/abseil-cpp/absl/debugging/stacktrace.h +++ b/third_party/abseil-cpp/absl/debugging/stacktrace.h @@ -1,5 +1,4 @@ -// -// Copyright 2017 The Abseil Authors. +// Copyright 2018 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. @@ -13,26 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. // - -// Routines to extract the current stack trace. These functions are -// thread-safe and async-signal-safe. +// ----------------------------------------------------------------------------- +// File: stacktrace.h +// ----------------------------------------------------------------------------- +// +// This file contains routines to extract the current stack trace and associated +// stack frames. These functions are thread-safe and async-signal-safe. +// // Note that stack trace functionality is platform dependent and requires -// additional support from the compiler/build system in many cases. (That is, -// this generally only works on platforms/builds that have been specifically -// configured to support it.) +// additional support from the compiler/build system in most cases. (That is, +// this functionality generally only works on platforms/builds that have been +// specifically configured to support it.) +// +// Note: stack traces in Abseil that do not utilize a symbolizer will result in +// frames consisting of function addresses rather than human-readable function +// names. (See symbolize.h for information on symbolizing these values.) #ifndef ABSL_DEBUGGING_STACKTRACE_H_ #define ABSL_DEBUGGING_STACKTRACE_H_ namespace absl { -// Skips the most recent "skip_count" stack frames (also skips the -// frame generated for the "absl::GetStackFrames" routine itself), and then -// records the pc values for up to the next "max_depth" frames in -// "result", and the corresponding stack frame sizes in "sizes". -// Returns the number of values recorded in "result"/"sizes". +// GetStackFrames() +// +// Records program counter values for up to `max_depth` frames, skipping the +// most recent `skip_count` stack frames, and stores their corresponding values +// and sizes in `results` and `sizes` buffers. (Note that the frame generated +// for the `absl::GetStackFrames()` routine itself is also skipped.) +// routine itself. // // Example: +// // main() { foo(); } // foo() { bar(); } // bar() { @@ -41,41 +51,66 @@ namespace absl { // int depth = absl::GetStackFrames(result, sizes, 10, 1); // } // -// The absl::GetStackFrames call will skip the frame for "bar". It will -// return 2 and will produce pc values that map to the following -// procedures: -// result[0] foo -// result[1] main -// (Actually, there may be a few more entries after "main" to account for -// startup procedures.) -// And corresponding stack frame sizes will also be recorded: +// The current stack frame would consist of three function calls: `bar()`, +// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets +// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently +// invoked function call. It will therefore return two program counters and will +// produce values that map to the following function calls: +// +// result[0] foo() +// result[1] main() +// +// (Note: in practice, a few more entries after `main()` may be added to account +// for startup processes.) +// +// Corresponding stack frame sizes will also be recorded: +// // sizes[0] 16 // sizes[1] 16 -// (Stack frame sizes of 16 above are just for illustration purposes.) +// +// (Stack frame sizes of `16` above are just for illustration purposes.) +// // Stack frame sizes of 0 or less indicate that those frame sizes couldn't // be identified. // // This routine may return fewer stack frame entries than are -// available. Also note that "result" and "sizes" must both be non-null. +// available. Also note that `result` and `sizes` must both be non-null. extern int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count); -// Same as above, but to be used from a signal handler. The "uc" parameter -// should be the pointer to ucontext_t which was passed as the 3rd parameter -// to sa_sigaction signal handler. It may help the unwinder to get a -// better stack trace under certain conditions. The "uc" may safely be null. +// GetStackFramesWithContext() // -// If min_dropped_frames is not null, stores in *min_dropped_frames a -// lower bound on the number of dropped stack frames. The stored value is -// guaranteed to be >= 0. The number of real stack frames is guaranteed to -// be >= skip_count + max_depth + *min_dropped_frames. +// Records program counter values obtained from a signal handler. Records +// program counter values for up to `max_depth` frames, skipping the most recent +// `skip_count` stack frames, and stores their corresponding values and sizes in +// `results` and `sizes` buffers. (Note that the frame generated for the +// `absl::GetStackFramesWithContext()` routine itself is also skipped.) +// +// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value +// passed to a signal handler registered via the `sa_sigaction` field of a +// `sigaction` struct. (See +// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may +// help a stack unwinder to provide a better stack trace under certain +// conditions. `uc` may safely be null. +// +// The `min_dropped_frames` output parameter, if non-null, points to the +// location to note any dropped stack frames, if any, due to buffer limitations +// 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. extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, int skip_count, const void* uc, int* min_dropped_frames); -// This is similar to the absl::GetStackFrames routine, except that it returns -// the stack trace only, and not the stack frame sizes as well. +// GetStackTrace() +// +// Records program counter values for up to `max_depth` frames, skipping the +// most recent `skip_count` stack frames, and stores their corresponding values +// in `results`. Note that this function is similar to `absl::GetStackFrames()` +// except that it returns the stack trace only, and not stack frame sizes. +// // Example: +// // main() { foo(); } // foo() { bar(); } // bar() { @@ -84,42 +119,57 @@ extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, // } // // This produces: +// // result[0] foo // result[1] main // .... ... // -// "result" must not be null. +// `result` must not be null. extern int GetStackTrace(void** result, int max_depth, int skip_count); -// Same as above, but to be used from a signal handler. The "uc" parameter -// should be the pointer to ucontext_t which was passed as the 3rd parameter -// to sa_sigaction signal handler. It may help the unwinder to get a -// better stack trace under certain conditions. The "uc" may safely be null. +// GetStackTraceWithContext() // -// If min_dropped_frames is not null, stores in *min_dropped_frames a -// lower bound on the number of dropped stack frames. The stored value is -// guaranteed to be >= 0. The number of real stack frames is guaranteed to -// be >= skip_count + max_depth + *min_dropped_frames. +// Records program counter values obtained from a signal handler. Records +// program counter values for up to `max_depth` frames, skipping the most recent +// `skip_count` stack frames, and stores their corresponding values in +// `results`. (Note that the frame generated for the +// `absl::GetStackFramesWithContext()` routine itself is also skipped.) +// +// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value +// passed to a signal handler registered via the `sa_sigaction` field of a +// `sigaction` struct. (See +// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may +// help a stack unwinder to provide a better stack trace under certain +// conditions. `uc` may safely be null. +// +// The `min_dropped_frames` output parameter, if non-null, points to the +// location to note any dropped stack frames, if any, due to buffer limitations +// 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. extern int GetStackTraceWithContext(void** result, int max_depth, int skip_count, const void* uc, int* min_dropped_frames); -// Call this to provide a custom function for unwinding stack frames -// that will be used every time someone invokes one of the static +// SetStackUnwinder() +// +// Provides a custom function for unwinding stack frames that will be used in +// place of the default stack unwinder when invoking the static // GetStack{Frames,Trace}{,WithContext}() functions above. // // The arguments passed to the unwinder function will match the -// arguments passed to absl::GetStackFramesWithContext() except that sizes +// arguments passed to `absl::GetStackFramesWithContext()` except that sizes // will be non-null iff the caller is interested in frame sizes. // -// If unwinder is null, we revert to the default stack-tracing behavior. +// If unwinder is set to null, we revert to the default stack-tracing behavior. // -// **************************************************************** -// WARNINGS +// ***************************************************************************** +// WARNING +// ***************************************************************************** // // absl::SetStackUnwinder is not suitable for general purpose use. It is // provided for custom runtimes. -// Some things to watch out for when calling absl::SetStackUnwinder: +// Some things to watch out for when calling `absl::SetStackUnwinder()`: // // (a) The unwinder may be called from within signal handlers and // therefore must be async-signal-safe. @@ -128,23 +178,31 @@ extern int GetStackTraceWithContext(void** result, int max_depth, // threads may still be in the process of using that unwinder. // Therefore do not clean up any state that may be needed by an old // unwinder. -// **************************************************************** +// ***************************************************************************** extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes, int max_depth, int skip_count, const void* uc, int* min_dropped_frames)); -// Function that exposes built-in stack-unwinding behavior, ignoring -// any calls to absl::SetStackUnwinder(). +// DefaultStackUnwinder() // -// pcs must NOT be null. +// Records program counter values of up to `max_depth` frames, skipping the most +// recent `skip_count` stack frames, and stores their corresponding values in +// `pcs`. (Note that the frame generated for this call itself is also skipped.) +// This function acts as a generic stack-unwinder; prefer usage of the more +// specific `GetStack{Trace,Frames}{,WithContext}()` functions above. // -// sizes may be null. -// uc may be null. -// min_dropped_frames may be null. +// If you have set your own stack unwinder (with the `SetStackUnwinder()` +// function above, you can still get the default stack unwinder by calling +// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder +// and use the default one instead. // -// The semantics are the same as the corresponding GetStack*() function in the -// case where absl::SetStackUnwinder() was never called. Equivalents are: +// Because this function is generic, only `pcs` is guaranteed to be non-null +// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all +// be null when called. +// +// The semantics are the same as the corresponding `GetStack*()` function in the +// case where `absl::SetStackUnwinder()` was never called. Equivalents are: // // null sizes | non-nullptr sizes // |==========================================================| diff --git a/third_party/abseil-cpp/absl/debugging/symbolize.cc b/third_party/abseil-cpp/absl/debugging/symbolize.cc index 355bf9ff95..a35e24cc29 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize.cc +++ b/third_party/abseil-cpp/absl/debugging/symbolize.cc @@ -14,8 +14,15 @@ #include "absl/debugging/symbolize.h" -#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) #include "absl/debugging/symbolize_elf.inc" +#elif defined(_WIN32) && defined(_DEBUG) +// The Windows Symbolizer only works in debug mode. Note that _DEBUG +// is the macro that defines whether or not MS C-Runtime debug info is +// available. Note that the PDB files containing the debug info must +// also be available to the program at runtime for the symbolizer to +// work. +#include "absl/debugging/symbolize_win32.inc" #else #include "absl/debugging/symbolize_unimplemented.inc" #endif diff --git a/third_party/abseil-cpp/absl/debugging/symbolize.h b/third_party/abseil-cpp/absl/debugging/symbolize.h index 073a4479d9..24e6e6471c 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize.h +++ b/third_party/abseil-cpp/absl/debugging/symbolize.h @@ -11,7 +11,44 @@ // 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. - +// +// ----------------------------------------------------------------------------- +// File: symbolize.h +// ----------------------------------------------------------------------------- +// +// This file configures the Abseil symbolizer for use in converting instruction +// pointer addresses (program counters) into human-readable names (function +// calls, etc.) within Abseil code. +// +// The symbolizer may be invoked from several sources: +// +// * Implicitly, through the installation of an Abseil failure signal handler. +// (See failure_signal_handler.h for more information.) +// * By calling `Symbolize()` directly on a program counter you obtain through +// `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h +// for more information. +// * By calling `Symbolize()` directly on a program counter you obtain through +// other means (which would be platform-dependent). +// +// In all of the above cases, the symbolizer must first be initialized before +// any program counter values can be symbolized. If you are installing a failure +// signal handler, initialize the symbolizer before you do so. +// +// Example: +// +// int main(int argc, char** argv) { +// // Initialize the Symbolizer before installing the failure signal handler +// absl::InitializeSymbolizer(argv[0]); +// +// // Now you may install the failure signal handler +// absl::FailureSignalHandlerOptions options; +// absl::InstallFailureSignalHandler(options); +// +// // Start running your main program +// ... +// return 0; +// } +// #ifndef ABSL_DEBUGGING_SYMBOLIZE_H_ #define ABSL_DEBUGGING_SYMBOLIZE_H_ @@ -19,15 +56,40 @@ namespace absl { -// Initializes this module. Symbolize() may fail prior calling this function. -// `argv0` is the path to this program, which is usually obtained in main() -// though argv[0]. +// InitializeSymbolizer() +// +// Initializes the program counter symbolizer, given the path of the program +// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer +// allows you to read program counters (instruction pointer values) using their +// human-readable names within output such as stack traces. +// +// Example: +// +// int main(int argc, char *argv[]) { +// absl::InitializeSymbolizer(argv[0]); +// // Now you can use the symbolizer +// } void InitializeSymbolizer(const char* argv0); -// Symbolizes a program counter. On success, returns true and write the -// symbol name to "out". The symbol name is demangled if possible -// (supports symbols generated by GCC 3.x or newer), may be truncated, and -// will be '\0' terminated. Otherwise, returns false. +// Symbolize() +// +// Symbolizes a program counter (instruction pointer value) `pc` and, on +// success, writes the name to `out`. The symbol name is demangled, if possible. +// Note that the symbolized name may be truncated and will be NUL-terminated. +// Demangling is supported for symbols generated by GCC 3.x or newer). Returns +// `false` on failure. +// +// Example: +// +// // Print a program counter and its symbol name. +// static void DumpPCAndSymbol(void *pc) { +// char tmp[1024]; +// const char *symbol = "(unknown)"; +// if (absl::Symbolize(pc, tmp, sizeof(tmp))) { +// symbol = tmp; +// } +// absl::PrintF("%*p %s\n", pc, symbol); +// } bool Symbolize(const void *pc, char *out, int out_size); } // namespace absl diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc index b23a801199..5f2af47ee4 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc +++ b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc @@ -68,7 +68,7 @@ int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) regular_func() { +int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { return 0; } @@ -88,9 +88,7 @@ static volatile bool volatile_bool = false; // Force the binary to be large enough that a THP .text remap will succeed. static constexpr size_t kHpageSize = 1 << 21; const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( - ".text") = ""; - -#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE + .text) = ""; static char try_symbolize_buffer[4096]; @@ -120,6 +118,8 @@ static const char *TrySymbolize(void *pc) { return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer)); } +#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE + TEST(Symbolize, Cached) { // Compilers should give us pointers to them. EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); @@ -236,9 +236,9 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { const size_t kPageSize = 64 << 10; // We place a read-only symbols into the .text section and verify that we can // symbolize them and other symbols after remapping them. -const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") = +const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; -const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") = +const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { @@ -442,6 +442,45 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #endif } +#elif defined(_WIN32) && defined(_DEBUG) + +TEST(Symbolize, Basics) { + EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); + + // The name of an internal linkage symbol is not specified; allow either a + // mangled or an unmangled name here. + const char* static_func_symbol = TrySymbolize((void *)(&static_func)); + ASSERT_TRUE(static_func_symbol != nullptr); + EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr); + + EXPECT_TRUE(nullptr == TrySymbolize(nullptr)); +} + +TEST(Symbolize, Truncation) { + constexpr char kNonStaticFunc[] = "nonstatic_func"; + EXPECT_STREQ("nonstatic_func", + TrySymbolizeWithLimit((void *)(&nonstatic_func), + strlen(kNonStaticFunc) + 1)); + EXPECT_STREQ("nonstatic_...", + TrySymbolizeWithLimit((void *)(&nonstatic_func), + strlen(kNonStaticFunc) + 0)); + EXPECT_STREQ("nonstatic...", + TrySymbolizeWithLimit((void *)(&nonstatic_func), + strlen(kNonStaticFunc) - 1)); + EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5)); + EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4)); + EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3)); + EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2)); + EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1)); + EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0)); +} + +TEST(Symbolize, SymbolizeWithDemangling) { + const char* result = TrySymbolize((void *)(&Foo::func)); + ASSERT_TRUE(result != nullptr); + EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result; +} + #else // Symbolizer unimplemented TEST(Symbolize, Unimplemented) { diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc b/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc new file mode 100644 index 0000000000..e3fff74d49 --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc @@ -0,0 +1,74 @@ +// Copyright 2018 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 +// +// http://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. + +// See "Retrieving Symbol Information by Address": +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx + +#include +#include +#pragma comment(lib, "DbgHelp") + +#include +#include + +#include "absl/base/internal/raw_logging.h" + +namespace absl { + +static HANDLE process = NULL; + +void InitializeSymbolizer(const char *argv0) { + if (process != nullptr) { + return; + } + process = GetCurrentProcess(); + + // Symbols are not loaded until a reference is made requiring the + // symbols be loaded. This is the fastest, most efficient way to use + // the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME); + if (!SymInitialize(process, nullptr, true)) { + // GetLastError() returns a Win32 DWORD, but we assign to + // unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform + // initialization guarantees this is not a narrowing conversion. + const unsigned long long error{GetLastError()}; // NOLINT(runtime/int) + ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error); + } +} + +bool Symbolize(const void *pc, char *out, int out_size) { + if (out_size <= 0) { + return false; + } + std::aligned_storage::type buf; + SYMBOL_INFO *symbol = reinterpret_cast(&buf); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + if (!SymFromAddr(process, reinterpret_cast(pc), nullptr, symbol)) { + return false; + } + strncpy(out, symbol->Name, out_size); + if (out[out_size - 1] != '\0') { + // strncpy() does not '\0' terminate when it truncates. + static constexpr char kEllipsis[] = "..."; + int ellipsis_size = + std::min(sizeof(kEllipsis) - 1, out_size - 1); + memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); + out[out_size - 1] = '\0'; + } + return true; +} + +} // namespace absl diff --git a/third_party/abseil-cpp/absl/meta/CMakeLists.txt b/third_party/abseil-cpp/absl/meta/CMakeLists.txt index d56fced8aa..adb0ceb754 100644 --- a/third_party/abseil-cpp/absl/meta/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/meta/CMakeLists.txt @@ -32,6 +32,8 @@ list(APPEND TYPE_TRAITS_TEST_SRC absl_header_library( TARGET absl_meta + PUBLIC_LIBRARIES + absl::base EXPORT_NAME meta ) @@ -42,7 +44,8 @@ absl_test( SOURCES ${TYPE_TRAITS_TEST_SRC} PUBLIC_LIBRARIES - ${TYPE_TRAITS_TEST_PUBLIC_LIBRARIES} absl::meta + absl::base + absl::meta ) diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel index 13badb7b9c..1e52312b47 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.bazel +++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel @@ -84,6 +84,7 @@ cc_library( "internal/utf8.cc", ], hdrs = [ + "internal/bits.h", "internal/char_map.h", "internal/ostringstream.h", "internal/resize_uninitialized.h", diff --git a/third_party/abseil-cpp/absl/strings/BUILD.gn b/third_party/abseil-cpp/absl/strings/BUILD.gn index 798a3b3fb6..2f73f5d8fe 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.gn +++ b/third_party/abseil-cpp/absl/strings/BUILD.gn @@ -76,6 +76,7 @@ source_set("internal") { "internal/utf8.cc", ] public = [ + "internal/bits.h", "internal/char_map.h", "internal/ostringstream.h", "internal/resize_uninitialized.h", diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt index 83cb934dba..9dc47328c7 100644 --- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt @@ -31,6 +31,7 @@ list(APPEND STRINGS_PUBLIC_HEADERS list(APPEND STRINGS_INTERNAL_HEADERS + "internal/bits.h" "internal/char_map.h" "internal/memutil.h" "internal/ostringstream.h" diff --git a/third_party/abseil-cpp/absl/strings/internal/bits.h b/third_party/abseil-cpp/absl/strings/internal/bits.h new file mode 100644 index 0000000000..901082ccdd --- /dev/null +++ b/third_party/abseil-cpp/absl/strings/internal/bits.h @@ -0,0 +1,53 @@ +// Copyright 2018 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 +// +// http://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_BITS_H_ +#define ABSL_STRINGS_INTERNAL_BITS_H_ + +#include + +#if defined(_MSC_VER) && defined(_M_X64) +#include +#pragma intrinsic(_BitScanReverse64) +#endif + +namespace absl { +namespace strings_internal { + +// Returns the number of leading 0 bits in a 64-bit value. +inline int CountLeadingZeros64(uint64_t n) { +#if defined(__GNUC__) + static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) + "__builtin_clzll does not take 64bit arg"); + return n == 0 ? 64 : __builtin_clzll(n); +#elif defined(_MSC_VER) && defined(_M_X64) + unsigned long result; // NOLINT(runtime/int) + if (_BitScanReverse64(&result, n)) { + return 63 - result; + } + return 64; +#else + int zeroes = 60; + if (n >> 32) zeroes -= 32, n >>= 32; + if (n >> 16) zeroes -= 16, n >>= 16; + if (n >> 8) zeroes -= 8, n >>= 8; + if (n >> 4) zeroes -= 4, n >>= 4; + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes; +#endif +} + +} // namespace strings_internal +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_BITS_H_ diff --git a/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h b/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h index c5fdc287cb..a734758c21 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h +++ b/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h @@ -234,17 +234,19 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, result_size += it->size(); } - STLStringResizeUninitialized(&result, result_size); + if (result_size > 0) { + STLStringResizeUninitialized(&result, result_size); - // Joins strings - char* result_buf = &*result.begin(); - memcpy(result_buf, start->data(), start->size()); - result_buf += start->size(); - for (Iterator it = start; ++it != end;) { - memcpy(result_buf, s.data(), s.size()); - result_buf += s.size(); - memcpy(result_buf, it->data(), it->size()); - result_buf += it->size(); + // Joins strings + char* result_buf = &*result.begin(); + memcpy(result_buf, start->data(), start->size()); + result_buf += start->size(); + for (Iterator it = start; ++it != end;) { + memcpy(result_buf, s.data(), s.size()); + result_buf += s.size(); + memcpy(result_buf, it->data(), it->size()); + result_buf += it->size(); + } } } diff --git a/third_party/abseil-cpp/absl/strings/match.h b/third_party/abseil-cpp/absl/strings/match.h index 6005533c99..108b6048b0 100644 --- a/third_party/abseil-cpp/absl/strings/match.h +++ b/third_party/abseil-cpp/absl/strings/match.h @@ -43,8 +43,7 @@ namespace absl { // // Returns whether a given std::string `haystack` contains the substring `needle`. inline bool StrContains(absl::string_view haystack, absl::string_view needle) { - return static_cast(haystack.find(needle, 0)) != - haystack.npos; + return haystack.find(needle, 0) != haystack.npos; } // StartsWith() diff --git a/third_party/abseil-cpp/absl/strings/numbers.cc b/third_party/abseil-cpp/absl/strings/numbers.cc index b4140b3605..68ef7999a9 100644 --- a/third_party/abseil-cpp/absl/strings/numbers.cc +++ b/third_party/abseil-cpp/absl/strings/numbers.cc @@ -32,6 +32,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/strings/ascii.h" +#include "absl/strings/internal/bits.h" #include "absl/strings/internal/memutil.h" #include "absl/strings/str_cat.h" @@ -302,18 +303,6 @@ char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { return numbers_internal::FastIntToBuffer(u, buffer); } -// Returns the number of leading 0 bits in a 64-bit value. -// TODO(jorg): Replace with builtin_clzll if available. -// Are we shipping util/bits in absl? -static inline int CountLeadingZeros64(uint64_t n) { - int zeroes = 60; - if (n >> 32) zeroes -= 32, n >>= 32; - if (n >> 16) zeroes -= 16, n >>= 16; - if (n >> 8) zeroes -= 8, n >>= 8; - if (n >> 4) zeroes -= 4, n >>= 4; - return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes; -} - // Given a 128-bit number expressed as a pair of uint64_t, high half first, // return that number multiplied by the given 32-bit value. If the result is // too large to fit in a 128-bit number, divide it by 2 until it fits. @@ -351,7 +340,7 @@ static std::pair Mul32(std::pair num, uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); if (bits128_up == 0) return {bits64_127, bits0_63}; - int shift = 64 - CountLeadingZeros64(bits128_up); + int shift = 64 - strings_internal::CountLeadingZeros64(bits128_up); uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); return {hi, lo}; @@ -382,7 +371,7 @@ static std::pair PowFive(uint64_t num, int expfive) { 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; result = Mul32(result, powers_of_five[expfive & 15]); - int shift = CountLeadingZeros64(result.first); + int shift = strings_internal::CountLeadingZeros64(result.first); if (shift != 0) { result.first = (result.first << shift) + (result.second >> (64 - shift)); result.second = (result.second << shift); diff --git a/third_party/abseil-cpp/absl/strings/str_cat.h b/third_party/abseil-cpp/absl/strings/str_cat.h index e38369cab7..e5501a5012 100644 --- a/third_party/abseil-cpp/absl/strings/str_cat.h +++ b/third_party/abseil-cpp/absl/strings/str_cat.h @@ -80,7 +80,7 @@ struct AlphaNumBuffer { // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, // would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value // would produce hexadecimal strings such as " A"," F". -enum PadSpec { +enum PadSpec : uint8_t { kNoPad = 1, kZeroPad2, kZeroPad3, diff --git a/third_party/abseil-cpp/absl/strings/str_join_test.cc b/third_party/abseil-cpp/absl/strings/str_join_test.cc index 03b60f03c8..c941f9c80d 100644 --- a/third_party/abseil-cpp/absl/strings/str_join_test.cc +++ b/third_party/abseil-cpp/absl/strings/str_join_test.cc @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/third_party/abseil-cpp/absl/strings/string_view.cc b/third_party/abseil-cpp/absl/strings/string_view.cc index 0e1729546a..4ceeb6bff5 100644 --- a/third_party/abseil-cpp/absl/strings/string_view.cc +++ b/third_party/abseil-cpp/absl/strings/string_view.cc @@ -22,8 +22,6 @@ #include #include "absl/strings/internal/memutil.h" -#include "absl/strings/internal/resize_uninitialized.h" -#include "absl/strings/match.h" namespace absl { diff --git a/third_party/abseil-cpp/absl/strings/string_view.h b/third_party/abseil-cpp/absl/strings/string_view.h index 9162bb33d4..a7f9199240 100644 --- a/third_party/abseil-cpp/absl/strings/string_view.h +++ b/third_party/abseil-cpp/absl/strings/string_view.h @@ -36,7 +36,7 @@ namespace absl { using std::string_view; -}; +} // namespace absl #else // ABSL_HAVE_STD_STRING_VIEW diff --git a/third_party/abseil-cpp/absl/strings/substitute.cc b/third_party/abseil-cpp/absl/strings/substitute.cc index f739f8c20b..3b20059450 100644 --- a/third_party/abseil-cpp/absl/strings/substitute.cc +++ b/third_party/abseil-cpp/absl/strings/substitute.cc @@ -94,6 +94,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, assert(target == output->data() + output->size()); } +static const char kHexDigits[] = "0123456789abcdef"; Arg::Arg(const void* value) { static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, "fix sizeof(scratch_)"); @@ -102,7 +103,6 @@ Arg::Arg(const void* value) { } else { char* ptr = scratch_ + sizeof(scratch_); uintptr_t num = reinterpret_cast(value); - static const char kHexDigits[] = "0123456789abcdef"; do { *--ptr = kHexDigits[num & 0xf]; num >>= 4; @@ -113,5 +113,58 @@ Arg::Arg(const void* value) { } } +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Hex hex) { + char* const end = &scratch_[numbers_internal::kFastToBufferSize]; + char* writer = end; + uint64_t value = hex.value; + do { + *--writer = kHexDigits[value & 0xF]; + value >>= 4; + } while (value != 0); + + char* beg; + if (end - writer < hex.width) { + beg = end - hex.width; + std::fill_n(beg, writer - beg, hex.fill); + } else { + beg = writer; + } + + piece_ = absl::string_view(beg, end - beg); +} + +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Dec dec) { + assert(dec.width <= numbers_internal::kFastToBufferSize); + char* const end = &scratch_[numbers_internal::kFastToBufferSize]; + char* const minfill = end - dec.width; + char* writer = end; + uint64_t value = dec.value; + bool neg = dec.neg; + while (value > 9) { + *--writer = '0' + (value % 10); + value /= 10; + } + *--writer = '0' + value; + if (neg) *--writer = '-'; + + ptrdiff_t fillers = writer - minfill; + if (fillers > 0) { + // Tricky: if the fill character is ' ', then it's <+/-> + // But...: if the fill character is '0', then it's <+/-> + bool add_sign_again = false; + if (neg && dec.fill == '0') { // If filling with '0', + ++writer; // ignore the sign we just added + add_sign_again = true; // and re-add the sign later. + } + writer -= fillers; + std::fill_n(writer, fillers, dec.fill); + if (add_sign_again) *--writer = '-'; + } + + piece_ = absl::string_view(writer, end - writer); +} + } // namespace substitute_internal } // namespace absl diff --git a/third_party/abseil-cpp/absl/strings/substitute.h b/third_party/abseil-cpp/absl/strings/substitute.h index 5596a5dbf3..5747d384d3 100644 --- a/third_party/abseil-cpp/absl/strings/substitute.h +++ b/third_party/abseil-cpp/absl/strings/substitute.h @@ -76,7 +76,7 @@ #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/numbers.h" -#include "absl/strings/str_join.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" @@ -113,10 +113,10 @@ class Arg { // what to do. Arg(char value) // NOLINT(runtime/explicit) : piece_(scratch_, 1) { scratch_[0] = value; } - Arg(short value) // NOLINT(runtime/explicit) + Arg(short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned short value) // NOLINT(runtime/explicit) + Arg(unsigned short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} Arg(int value) // NOLINT(runtime/explicit) @@ -125,16 +125,16 @@ class Arg { Arg(unsigned int value) // NOLINT(runtime/explicit) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long value) // NOLINT(runtime/explicit) + Arg(long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long value) // NOLINT(runtime/explicit) + Arg(unsigned long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long long value) // NOLINT(runtime/explicit) + Arg(long long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long long value) // NOLINT(runtime/explicit) + Arg(unsigned long long value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} Arg(float value) // NOLINT(runtime/explicit) @@ -145,6 +145,10 @@ class Arg { } Arg(bool value) // NOLINT(runtime/explicit) : piece_(value ? "true" : "false") {} + + Arg(Hex hex); // NOLINT(runtime/explicit) + Arg(Dec dec); // NOLINT(runtime/explicit) + // `void*` values, with the exception of `char*`, are printed as // "0x". However, in the case of `nullptr`, "NULL" is printed. Arg(const void* value); // NOLINT(runtime/explicit) diff --git a/third_party/abseil-cpp/absl/strings/substitute_test.cc b/third_party/abseil-cpp/absl/strings/substitute_test.cc index 7c9af6b224..144df01ec1 100644 --- a/third_party/abseil-cpp/absl/strings/substitute_test.cc +++ b/third_party/abseil-cpp/absl/strings/substitute_test.cc @@ -43,6 +43,24 @@ TEST(SubstituteTest, Substitute) { -1234567890, 3234567890U, -1234567890L, 3234567890UL, -int64_t{1234567890123456789}, uint64_t{9234567890123456789u})); + // Hex format + EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef", + absl::Substitute("$0$1$2$3$4 $5", // + absl::Hex(0), absl::Hex(1, absl::kSpacePad2), + absl::Hex(0xf, absl::kSpacePad2), + absl::Hex(int16_t{-1}, absl::kSpacePad5), + absl::Hex(int16_t{-1}, absl::kZeroPad5), + absl::Hex(0x123456789abcdef, absl::kZeroPad16))); + + // Dec format + EXPECT_EQ("0 115 -1-0001 81985529216486895", + absl::Substitute("$0$1$2$3$4 $5", // + absl::Dec(0), absl::Dec(1, absl::kSpacePad2), + absl::Dec(0xf, absl::kSpacePad2), + absl::Dec(int16_t{-1}, absl::kSpacePad5), + absl::Dec(int16_t{-1}, absl::kZeroPad5), + absl::Dec(0x123456789abcdef, absl::kZeroPad16))); + // Pointer. const int* int_p = reinterpret_cast(0x12345); std::string str = absl::Substitute("$0", int_p); diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel index 69f9c81f6f..05376903fe 100644 --- a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel +++ b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel @@ -77,6 +77,7 @@ cc_library( "//absl/base:dynamic_annotations", "//absl/base:malloc_internal", "//absl/debugging:stacktrace", + "//absl/debugging:symbolize", "//absl/time", ], ) diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.gn b/third_party/abseil-cpp/absl/synchronization/BUILD.gn index 65f9d3bb49..dfca941366 100644 --- a/third_party/abseil-cpp/absl/synchronization/BUILD.gn +++ b/third_party/abseil-cpp/absl/synchronization/BUILD.gn @@ -73,6 +73,7 @@ source_set("synchronization") { "../base:dynamic_annotations", "../base:malloc_internal", "../debugging:stacktrace", + "../debugging:symbolize", "../time", ] } diff --git a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt index c8f84faf8b..c19f572592 100644 --- a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt @@ -33,7 +33,7 @@ list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS -# syncrhonisation library +# synchronization library list(APPEND SYNCHRONIZATION_SRC "barrier.cc" "blocking_counter.cc" @@ -44,7 +44,8 @@ list(APPEND SYNCHRONIZATION_SRC "notification.cc" "mutex.cc" ) -set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::time) + +set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time) absl_library( TARGET diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc index 3c3e939051..a207b71fcd 100644 --- a/third_party/abseil-cpp/absl/synchronization/mutex.cc +++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc @@ -50,6 +50,7 @@ #include "absl/base/internal/thread_identity.h" #include "absl/base/port.h" #include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" #include "absl/synchronization/internal/graphcycles.h" #include "absl/synchronization/internal/per_thread_sem.h" #include "absl/time/time.h" @@ -111,7 +112,8 @@ ABSL_CONST_INIT absl::base_internal::AtomicHook< ABSL_CONST_INIT absl::base_internal::AtomicHook< void (*)(const char *msg, const void *cv)> cond_var_tracer; ABSL_CONST_INIT absl::base_internal::AtomicHook< - bool (*)(const void *pc, char *out, int out_size)> symbolizer; + bool (*)(const void *pc, char *out, int out_size)> + symbolizer(absl::Symbolize); } // namespace diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h index c4e026f9b9..368684bf2e 100644 --- a/third_party/abseil-cpp/absl/synchronization/mutex.h +++ b/third_party/abseil-cpp/absl/synchronization/mutex.h @@ -979,6 +979,12 @@ void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)); // to 'out.' // // This has the same memory ordering concerns as RegisterMutexProfiler() above. +// +// DEPRECATED: The default symbolizer function is absl::Symbolize() and the +// ability to register a different hook for symbolizing stack traces will be +// removed on or after 2023-05-01. +ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed " + "on or after 2023-05-01") void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)); // EnableMutexInvariantDebugging() diff --git a/third_party/abseil-cpp/absl/time/BUILD.bazel b/third_party/abseil-cpp/absl/time/BUILD.bazel index d4f653f40f..7126f1410f 100644 --- a/third_party/abseil-cpp/absl/time/BUILD.bazel +++ b/third_party/abseil-cpp/absl/time/BUILD.bazel @@ -51,6 +51,7 @@ cc_library( cc_library( name = "test_util", + testonly = 1, srcs = [ "internal/test_util.cc", "internal/zoneinfo.inc", @@ -64,6 +65,7 @@ cc_library( ":time", "//absl/base", "//absl/time/internal/cctz:time_zone", + "@com_google_googletest//:gtest", ], ) diff --git a/third_party/abseil-cpp/absl/time/BUILD.gn b/third_party/abseil-cpp/absl/time/BUILD.gn index d440aaac75..9f728f4101 100644 --- a/third_party/abseil-cpp/absl/time/BUILD.gn +++ b/third_party/abseil-cpp/absl/time/BUILD.gn @@ -45,6 +45,7 @@ source_set("time") { } source_set("test_util") { + testonly = true configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code", @@ -62,6 +63,8 @@ source_set("test_util") { ":time", "../base", "../time/internal/cctz:time_zone", + "//testing/gtest", + "//testing/gmock", ] visibility = [] visibility += [ "../time:*" ] diff --git a/third_party/abseil-cpp/absl/time/format_test.cc b/third_party/abseil-cpp/absl/time/format_test.cc index 09d1fe6666..7c84c33f1e 100644 --- a/third_party/abseil-cpp/absl/time/format_test.cc +++ b/third_party/abseil-cpp/absl/time/format_test.cc @@ -155,8 +155,7 @@ TEST(ParseTime, Basics) { "2013-06-28 19:08:09 -0800", &t, &err)) << err; absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60)); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false, - "UTC-8"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false); EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); } @@ -179,8 +178,7 @@ TEST(ParseTime, WithTimeZone) { absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e)) << e; absl::Time::Breakdown bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, - "PDT"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true); EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); // But the timezone is ignored when a UTC offset is present. @@ -188,8 +186,7 @@ TEST(ParseTime, WithTimeZone) { "2013-06-28 19:08:09 +0800", tz, &t, &e)) << e; bd = t.In(absl::FixedTimeZone(8 * 60 * 60)); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false, - "UTC+8"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false); EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); } diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel b/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel index fe17b3e31b..468470b4fb 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel +++ b/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel @@ -80,6 +80,7 @@ cc_test( name = "time_zone_format_test", size = "small", srcs = ["src/time_zone_format_test.cc"], + data = [":zoneinfo"], deps = [ ":civil_time", ":time_zone", @@ -91,6 +92,7 @@ cc_test( name = "time_zone_lookup_test", size = "small", srcs = ["src/time_zone_lookup_test.cc"], + data = [":zoneinfo"], deps = [ ":civil_time", ":time_zone", @@ -103,3 +105,8 @@ cc_test( ### examples ### binaries + +filegroup( + name = "zoneinfo", + srcs = glob(["testdata/zoneinfo/**"]), +) diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h index 4c39c7d120..d52eddcdba 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h +++ b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h @@ -20,8 +20,8 @@ #include #include -// Disable constexpr support unless we are using clang in C++14 mode. -#if __clang__ && __cpp_constexpr >= 201304 +// Disable constexpr support unless we are in C++14 mode. +#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 #define CONSTEXPR_D constexpr // data #define CONSTEXPR_F constexpr // function #define CONSTEXPR_M constexpr // member diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc index 6df0395bad..f6648c8f1f 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc +++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc @@ -37,7 +37,7 @@ std::string Format(const T& t) { } // namespace -#if __clang__ && __cpp_constexpr >= 201304 +#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 // Construction constexpr tests TEST(CivilTime, Normal) { @@ -319,7 +319,7 @@ TEST(CivilTime, YearDay) { constexpr int yd = get_yearday(cd); static_assert(yd == 28, "YearDay"); } -#endif // __clang__ && __cpp_constexpr >= 201304 +#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910 // The remaining tests do not use constexpr. diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc index 8d3b144252..65eba3569d 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc +++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc @@ -27,7 +27,7 @@ namespace cctz { namespace { // The prefix used for the internal names of fixed-offset zones. -const char kFixedOffsetPrefix[] = "Fixed/"; +const char kFixedOffsetPrefix[] = "Fixed/UTC"; int Parse02d(const char* p) { static const char kDigits[] = "0123456789"; @@ -50,13 +50,11 @@ bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) { const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1; const char* const ep = kFixedOffsetPrefix + prefix_len; - if (name.size() != prefix_len + 12) // "UTC+99:99:99" + if (name.size() != prefix_len + 9) // +99:99:99 return false; if (!std::equal(kFixedOffsetPrefix, ep, name.begin())) return false; const char* np = name.data() + prefix_len; - if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C') - return false; if (np[0] != '+' && np[0] != '-') return false; if (np[3] != ':' || np[6] != ':') // see note below about large offsets @@ -97,8 +95,8 @@ std::string FixedOffsetToName(const sys_seconds& offset) { } int hours = minutes / 60; minutes %= 60; - char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")]; - snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d", + char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")]; + snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d", kFixedOffsetPrefix, sign, hours, minutes, seconds); return buf; } @@ -106,22 +104,14 @@ std::string FixedOffsetToName(const sys_seconds& offset) { std::string FixedOffsetToAbbr(const sys_seconds& offset) { std::string abbr = FixedOffsetToName(offset); const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1; - const char* const ep = kFixedOffsetPrefix + prefix_len; - if (abbr.size() >= prefix_len) { - if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) { - abbr.erase(0, prefix_len); - if (abbr.size() == 12) { // UTC+99:99:99 - abbr.erase(9, 1); // UTC+99:9999 - abbr.erase(6, 1); // UTC+999999 - if (abbr[8] == '0' && abbr[9] == '0') { // UTC+999900 - abbr.erase(8, 2); // UTC+9999 - if (abbr[6] == '0' && abbr[7] == '0') { // UTC+9900 - abbr.erase(6, 2); // UTC+99 - if (abbr[4] == '0') { // UTC+09 - abbr.erase(4, 1); // UTC+9 - } - } - } + if (abbr.size() == prefix_len + 9) { // +99:99:99 + abbr.erase(0, prefix_len); // +99:99:99 + abbr.erase(6, 1); // +99:9999 + abbr.erase(3, 1); // +999999 + if (abbr[5] == '0' && abbr[6] == '0') { // +999900 + abbr.erase(5, 2); // +9999 + if (abbr[3] == '0' && abbr[4] == '0') { // +9900 + abbr.erase(3, 2); // +99 } } } diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc index fbd86e16b4..d549d862a7 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -134,6 +134,9 @@ time_zone local_time_zone() { time_zone tz; load_time_zone(name, &tz); // Falls back to UTC. + // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and + // arrange for %z to generate "-0000" when we don't know the local + // offset because the load_time_zone() failed and we're using UTC. return tz; } diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc index a5d73d5492..f97eab0227 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -415,7 +415,6 @@ const char* const kTimeZoneNames[] = { "CST6CDT", "Canada/Atlantic", "Canada/Central", - "Canada/East-Saskatchewan", "Canada/Eastern", "Canada/Mountain", "Canada/Newfoundland", @@ -1119,18 +1118,6 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) { auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz); ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT"); tp += seconds(1); -#ifndef TZDATA_2017B_IS_UBIQUITOUS - // The 2017b tzdata release moved the shift from -004430 to +00 - // from 1972-05-01 to 1972-01-07, so we temporarily accept both - // outcomes until 2017b is ubiquitous. - if (tz.lookup(tp).offset == -44.5 * 60) { - tp = convert(civil_second(1972, 4, 30, 23, 59, 59), tz); - ExpectTime(tp, tz, 1972, 4, 30, 23, 59, 59, -44.5 * 60, false, "LRT"); - tp += seconds(1); - ExpectTime(tp, tz, 1972, 5, 1, 0, 44, 30, 0 * 60, false, "GMT"); - return; - } -#endif ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT"); } diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version index 05c3ec2807..fe86b5cc87 100644 --- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version +++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version @@ -1 +1 @@ -2018d-2-g8d1dac0 +2018e-2-g99dd695 diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek index 358f11e329..f5d40bafc3 100644 Binary files a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek and b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek differ diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang index de5c2b1566..dc24926e80 100644 Binary files a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang and b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang differ diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava index 4eabe5c81b..ba82f311b7 100644 Binary files a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava and b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava differ diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague index 4eabe5c81b..ba82f311b7 100644 Binary files a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague and b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague differ diff --git a/third_party/abseil-cpp/absl/time/internal/test_util.cc b/third_party/abseil-cpp/absl/time/internal/test_util.cc index 4483f2a977..bbbef7da70 100644 --- a/third_party/abseil-cpp/absl/time/internal/test_util.cc +++ b/third_party/abseil-cpp/absl/time/internal/test_util.cc @@ -26,6 +26,12 @@ namespace cctz = absl::time_internal::cctz; namespace absl { namespace time_internal { +#if GTEST_USES_SIMPLE_RE +extern const char kZoneAbbrRE[] = ".*"; // just punt +#else +extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?"; +#endif + TimeZone LoadTimeZone(const std::string& name) { TimeZone tz; ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str()); diff --git a/third_party/abseil-cpp/absl/time/internal/test_util.h b/third_party/abseil-cpp/absl/time/internal/test_util.h index 81a2d29de1..8fd5fb9fd0 100644 --- a/third_party/abseil-cpp/absl/time/internal/test_util.h +++ b/third_party/abseil-cpp/absl/time/internal/test_util.h @@ -17,6 +17,8 @@ #include +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "absl/time/time.h" // This helper is a macro so that failed expectations show up with the @@ -24,22 +26,26 @@ // // This is for internal testing of the Base Time library itself. This is not // part of a public API. -#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst, zone) \ - do { \ - EXPECT_EQ(y, bd.year); \ - EXPECT_EQ(m, bd.month); \ - EXPECT_EQ(d, bd.day); \ - EXPECT_EQ(h, bd.hour); \ - EXPECT_EQ(min, bd.minute); \ - EXPECT_EQ(s, bd.second); \ - EXPECT_EQ(off, bd.offset); \ - EXPECT_EQ(isdst, bd.is_dst); \ - EXPECT_STREQ(zone, bd.zone_abbr); \ +#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \ + do { \ + EXPECT_EQ(y, bd.year); \ + EXPECT_EQ(m, bd.month); \ + EXPECT_EQ(d, bd.day); \ + EXPECT_EQ(h, bd.hour); \ + EXPECT_EQ(min, bd.minute); \ + EXPECT_EQ(s, bd.second); \ + EXPECT_EQ(off, bd.offset); \ + EXPECT_EQ(isdst, bd.is_dst); \ + EXPECT_THAT(bd.zone_abbr, \ + testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \ } while (0) namespace absl { namespace time_internal { +// A regular expression that matches all zone abbreviations (%Z). +extern const char kZoneAbbrRE[]; + // Loads the named timezone, but dies on any failure. absl::TimeZone LoadTimeZone(const std::string& name); diff --git a/third_party/abseil-cpp/absl/time/time.cc b/third_party/abseil-cpp/absl/time/time.cc index 1dde40d7e2..03720f62b0 100644 --- a/third_party/abseil-cpp/absl/time/time.cc +++ b/third_party/abseil-cpp/absl/time/time.cc @@ -71,7 +71,7 @@ inline absl::Time::Breakdown InfiniteFutureBreakdown() { bd.yearday = 365; bd.offset = 0; bd.is_dst = false; - bd.zone_abbr = "-0000"; + bd.zone_abbr = "-00"; return bd; } @@ -88,7 +88,7 @@ inline Time::Breakdown InfinitePastBreakdown() { bd.yearday = 1; bd.offset = 0; bd.is_dst = false; - bd.zone_abbr = "-0000"; + bd.zone_abbr = "-00"; return bd; } diff --git a/third_party/abseil-cpp/absl/time/time_norm_test.cc b/third_party/abseil-cpp/absl/time/time_norm_test.cc index 005756e6df..4436242e41 100644 --- a/third_party/abseil-cpp/absl/time/time_norm_test.cc +++ b/third_party/abseil-cpp/absl/time/time_norm_test.cc @@ -18,6 +18,7 @@ #include #include +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/internal/test_util.h" #include "absl/time/time.h" @@ -32,31 +33,31 @@ TEST(TimeNormCase, SimpleOverflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false); } TEST(TimeNormCase, SimpleUnderflow) { @@ -66,31 +67,31 @@ TEST(TimeNormCase, SimpleUnderflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false); tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false); tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false); tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false); tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false); } TEST(TimeNormCase, MultipleOverflow) { @@ -99,7 +100,7 @@ TEST(TimeNormCase, MultipleOverflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false); } TEST(TimeNormCase, MultipleUnderflow) { @@ -108,7 +109,7 @@ TEST(TimeNormCase, MultipleUnderflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false); } TEST(TimeNormCase, OverflowLimits) { @@ -122,7 +123,7 @@ TEST(TimeNormCase, OverflowLimits) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false); const int kintmin = std::numeric_limits::min(); tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin, @@ -130,8 +131,7 @@ TEST(TimeNormCase, OverflowLimits) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false, - "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false); const int64_t max_year = std::numeric_limits::max(); tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc); @@ -154,31 +154,31 @@ TEST(TimeNormCase, ComplexOverflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false); } TEST(TimeNormCase, ComplexUnderflow) { @@ -189,37 +189,37 @@ TEST(TimeNormCase, ComplexUnderflow) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false); tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false); } TEST(TimeNormCase, Mishmash) { @@ -231,14 +231,14 @@ TEST(TimeNormCase, Mishmash) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false); tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456, 32 - 1234567, 14 + 123456789, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false); // Here is a normalization case we got wrong for a while. Because the // day is converted to "1" within a 400-year (146097-day) period, we @@ -247,7 +247,7 @@ TEST(TimeNormCase, Mishmash) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false); // Even though the month overflow compensates for the day underflow, // this should still be marked as normalized. @@ -255,7 +255,7 @@ TEST(TimeNormCase, Mishmash) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false); } TEST(TimeNormCase, LeapYears) { @@ -266,25 +266,25 @@ TEST(TimeNormCase, LeapYears) { EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false); tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc); EXPECT_FALSE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false); tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc); EXPECT_FALSE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false); tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc); EXPECT_TRUE(tc.normalized); EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false); } // Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31) diff --git a/third_party/abseil-cpp/absl/time/time_test.cc b/third_party/abseil-cpp/absl/time/time_test.cc index 64083880c1..4f8f58a6ef 100644 --- a/third_party/abseil-cpp/absl/time/time_test.cc +++ b/third_party/abseil-cpp/absl/time/time_test.cc @@ -85,7 +85,7 @@ TEST(Time, ValueSemantics) { TEST(Time, UnixEpoch) { absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone()); - ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false); EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); EXPECT_EQ(4, bd.weekday); // Thursday } @@ -96,14 +96,14 @@ TEST(Time, Breakdown) { // The Unix epoch as seen in NYC. absl::Time::Breakdown bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false, "EST"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false); EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); EXPECT_EQ(3, bd.weekday); // Wednesday // Just before the epoch. t -= absl::Nanoseconds(1); bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false, "EST"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false); EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond); EXPECT_EQ(3, bd.weekday); // Wednesday @@ -112,7 +112,7 @@ TEST(Time, Breakdown) { t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) + absl::Nanoseconds(9); bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true, "EDT"); + ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true); EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1)); EXPECT_EQ(2, bd.weekday); // Tuesday } @@ -983,16 +983,18 @@ TEST(Time, ConversionSaturation) { // Checks how Time::In() saturates on infinities. absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc); ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits::max(), 12, 31, 23, - 59, 59, 0, false, "-0000"); + 59, 59, 0, false); EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond); EXPECT_EQ(4, bd.weekday); // Thursday EXPECT_EQ(365, bd.yearday); + EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() bd = absl::InfinitePast().In(utc); ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits::min(), 1, 1, 0, 0, - 0, 0, false, "-0000"); + 0, 0, false); EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond); EXPECT_EQ(7, bd.weekday); // Sunday EXPECT_EQ(1, bd.yearday); + EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() // Approach the maximal Time value from below. t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc); @@ -1054,13 +1056,11 @@ TEST(Time, ExtendedConversionSaturation) { // The maximal time converted in each zone. bd = max.In(syd); - ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true, - "AEDT"); + ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true); t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd); EXPECT_EQ(max, t); bd = max.In(nyc); - ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false, - "EST"); + ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false); t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc); EXPECT_EQ(max, t); diff --git a/third_party/abseil-cpp/absl/types/BUILD.bazel b/third_party/abseil-cpp/absl/types/BUILD.bazel index 0bdb2f78ae..f8d53c263b 100644 --- a/third_party/abseil-cpp/absl/types/BUILD.bazel +++ b/third_party/abseil-cpp/absl/types/BUILD.bazel @@ -223,3 +223,18 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "variant_exception_safety_test", + size = "small", + srcs = [ + "variant_exception_safety_test.cc", + ], + copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + deps = [ + ":variant", + "//absl/base:exception_safety_testing", + "//absl/memory", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/third_party/abseil-cpp/absl/types/CMakeLists.txt b/third_party/abseil-cpp/absl/types/CMakeLists.txt index f51d126f81..fbd8374031 100644 --- a/third_party/abseil-cpp/absl/types/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/types/CMakeLists.txt @@ -29,6 +29,9 @@ absl_header_library( TARGET absl_any PUBLIC_LIBRARIES + absl::bad_any_cast + absl::base + absl::meta absl::utility PRIVATE_COMPILE_FLAGS ${ABSL_EXCEPTIONS_FLAG} @@ -59,7 +62,6 @@ absl_library( SOURCES ${BAD_ANY_CAST_SRC} PUBLIC_LIBRARIES - absl::base absl::any EXPORT_NAME bad_any_cast ) @@ -76,7 +78,11 @@ absl_library( SOURCES ${OPTIONAL_SRC} PUBLIC_LIBRARIES + absl::bad_optional_access absl::base + absl::memory + absl::meta + absl::utility EXPORT_NAME optional ) @@ -143,7 +149,11 @@ absl_test( # test any_exception_safety_test set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc") -set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES absl::any absl::base absl::base_internal_exception_safety_testing) +set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES + absl::any + absl::base + absl_base_internal_exception_safety_testing +) absl_test( TARGET diff --git a/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc b/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc index 82c176b518..36955f6c5c 100644 --- a/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc +++ b/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc @@ -20,21 +20,16 @@ #include "gtest/gtest.h" #include "absl/base/internal/exception_safety_testing.h" -using Thrower = absl::ThrowingValue<>; +using Thrower = testing::ThrowingValue<>; using NoThrowMoveThrower = - absl::ThrowingValue; + testing::ThrowingValue; using ThrowerList = std::initializer_list; using ThrowerVec = std::vector; -using ThrowingAlloc = absl::ThrowingAllocator; +using ThrowingAlloc = testing::ThrowingAllocator; using ThrowingThrowerVec = std::vector; namespace { -class AnyExceptionSafety : public ::testing::Test { - private: - absl::ConstructorTracker inspector_; -}; - testing::AssertionResult AnyInvariants(absl::any* a) { using testing::AssertionFailure; using testing::AssertionSuccess; @@ -84,30 +79,33 @@ testing::AssertionResult AnyIsEmpty(absl::any* a) { << absl::any_cast(*a).Get(); } -TEST_F(AnyExceptionSafety, Ctors) { +TEST(AnyExceptionSafety, Ctors) { Thrower val(1); - auto with_val = absl::TestThrowingCtor(val); - auto copy = absl::TestThrowingCtor(with_val); - auto in_place = - absl::TestThrowingCtor(absl::in_place_type_t(), 1); - auto in_place_list = absl::TestThrowingCtor( - absl::in_place_type_t(), ThrowerList{val}); - auto in_place_list_again = - absl::TestThrowingCtor, - ThrowerList, ThrowingAlloc>( - absl::in_place_type_t(), {val}, ThrowingAlloc()); + testing::TestThrowingCtor(val); + + Thrower copy(val); + testing::TestThrowingCtor(copy); + + testing::TestThrowingCtor(absl::in_place_type_t(), 1); + + testing::TestThrowingCtor(absl::in_place_type_t(), + ThrowerList{val}); + + testing::TestThrowingCtor, + ThrowerList, ThrowingAlloc>( + absl::in_place_type_t(), {val}, ThrowingAlloc()); } -TEST_F(AnyExceptionSafety, Assignment) { +TEST(AnyExceptionSafety, Assignment) { auto original = - absl::any(absl::in_place_type_t(), 1, absl::no_throw_ctor); + absl::any(absl::in_place_type_t(), 1, testing::nothrow_ctor); auto any_is_strong = [original](absl::any* ap) { return testing::AssertionResult(ap->has_value() && absl::any_cast(original) == absl::any_cast(*ap)); }; - auto any_strong_tester = absl::MakeExceptionSafetyTester() + auto any_strong_tester = testing::MakeExceptionSafetyTester() .WithInitialValue(original) .WithInvariants(AnyInvariants, any_is_strong); @@ -129,7 +127,7 @@ TEST_F(AnyExceptionSafety, Assignment) { return testing::AssertionResult{!ap->has_value()}; }; auto strong_empty_any_tester = - absl::MakeExceptionSafetyTester() + testing::MakeExceptionSafetyTester() .WithInitialValue(absl::any{}) .WithInvariants(AnyInvariants, empty_any_is_strong); @@ -139,16 +137,16 @@ TEST_F(AnyExceptionSafety, Assignment) { } // libstdc++ std::any fails this test #if !defined(ABSL_HAVE_STD_ANY) -TEST_F(AnyExceptionSafety, Emplace) { +TEST(AnyExceptionSafety, Emplace) { auto initial_val = - absl::any{absl::in_place_type_t(), 1, absl::no_throw_ctor}; - auto one_tester = absl::MakeExceptionSafetyTester() + absl::any{absl::in_place_type_t(), 1, testing::nothrow_ctor}; + auto one_tester = testing::MakeExceptionSafetyTester() .WithInitialValue(initial_val) .WithInvariants(AnyInvariants, AnyIsEmpty); auto emp_thrower = [](absl::any* ap) { ap->emplace(2); }; auto emp_throwervec = [](absl::any* ap) { - std::initializer_list il{Thrower(2, absl::no_throw_ctor)}; + std::initializer_list il{Thrower(2, testing::nothrow_ctor)}; ap->emplace(il); }; auto emp_movethrower = [](absl::any* ap) { diff --git a/third_party/abseil-cpp/absl/types/optional.h b/third_party/abseil-cpp/absl/types/optional.h index 98b29e591d..80a2d149fc 100644 --- a/third_party/abseil-cpp/absl/types/optional.h +++ b/third_party/abseil-cpp/absl/types/optional.h @@ -776,10 +776,13 @@ class optional : private optional_internal::optional_data, // `optional` is empty, behavior is undefined. // // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. - const T* operator->() const { return this->pointer(); } + const T* operator->() const { + assert(this->engaged_); + return std::addressof(this->data_); + } T* operator->() { assert(this->engaged_); - return this->pointer(); + return std::addressof(this->data_); } // optional::operator*() @@ -817,6 +820,12 @@ class optional : private optional_internal::optional_data, // only if `*this` is empty. constexpr bool has_value() const noexcept { return this->engaged_; } +// Suppress bogus warning on MSVC: MSVC complains call to reference() after +// throw_bad_optional_access() is unreachable. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) +#endif // _MSC_VER // optional::value() // // Returns a reference to an `optional`s underlying value. The constness @@ -845,6 +854,9 @@ class optional : private optional_internal::optional_data, ? reference() : (optional_internal::throw_bad_optional_access(), reference())); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER // optional::value_or() // @@ -871,10 +883,6 @@ class optional : private optional_internal::optional_data, } private: - // Private accessors for internal storage viewed as pointer to T. - const T* pointer() const { return std::addressof(this->data_); } - T* pointer() { return std::addressof(this->data_); } - // Private accessors for internal storage viewed as reference to T. constexpr const T& reference() const { return this->data_; } T& reference() { return this->data_; } @@ -958,7 +966,8 @@ constexpr auto operator==(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x == *y)) { return static_cast(x) != static_cast(y) ? false - : static_cast(x) == false ? true : *x == *y; + : static_cast(x) == false ? true + : static_cast(*x == *y); } // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; @@ -968,31 +977,32 @@ constexpr auto operator!=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x != *y)) { return static_cast(x) != static_cast(y) ? true - : static_cast(x) == false ? false : *x != *y; + : static_cast(x) == false ? false + : static_cast(*x != *y); } // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. template constexpr auto operator<(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x < *y)) { - return !y ? false : !x ? true : *x < *y; + return !y ? false : !x ? true : static_cast(*x < *y); } // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. template constexpr auto operator>(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x > *y)) { - return !x ? false : !y ? true : *x > *y; + return !x ? false : !y ? true : static_cast(*x > *y); } // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. template constexpr auto operator<=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x <= *y)) { - return !x ? true : !y ? false : *x <= *y; + return !x ? true : !y ? false : static_cast(*x <= *y); } // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. template constexpr auto operator>=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x >= *y)) { - return !y ? true : !x ? false : *x >= *y; + return !y ? true : !x ? false : static_cast(*x >= *y); } // Comparison with nullopt [optional.nullops] @@ -1054,62 +1064,62 @@ constexpr bool operator>=(nullopt_t, const optional& x) noexcept { template constexpr auto operator==(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x == v)) { - return static_cast(x) ? *x == v : false; + return static_cast(x) ? static_cast(*x == v) : false; } template constexpr auto operator==(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v == *x)) { - return static_cast(x) ? v == *x : false; + return static_cast(x) ? static_cast(v == *x) : false; } template constexpr auto operator!=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x != v)) { - return static_cast(x) ? *x != v : true; + return static_cast(x) ? static_cast(*x != v) : true; } template constexpr auto operator!=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v != *x)) { - return static_cast(x) ? v != *x : true; + return static_cast(x) ? static_cast(v != *x) : true; } template constexpr auto operator<(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x < v)) { - return static_cast(x) ? *x < v : true; + return static_cast(x) ? static_cast(*x < v) : true; } template constexpr auto operator<(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v < *x)) { - return static_cast(x) ? v < *x : false; + return static_cast(x) ? static_cast(v < *x) : false; } template constexpr auto operator<=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x <= v)) { - return static_cast(x) ? *x <= v : true; + return static_cast(x) ? static_cast(*x <= v) : true; } template constexpr auto operator<=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v <= *x)) { - return static_cast(x) ? v <= *x : false; + return static_cast(x) ? static_cast(v <= *x) : false; } template constexpr auto operator>(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x > v)) { - return static_cast(x) ? *x > v : false; + return static_cast(x) ? static_cast(*x > v) : false; } template constexpr auto operator>(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v > *x)) { - return static_cast(x) ? v > *x : true; + return static_cast(x) ? static_cast(v > *x) : true; } template constexpr auto operator>=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x >= v)) { - return static_cast(x) ? *x >= v : false; + return static_cast(x) ? static_cast(*x >= v) : false; } template constexpr auto operator>=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v >= *x)) { - return static_cast(x) ? v >= *x : true; + return static_cast(x) ? static_cast(v >= *x) : true; } } // namespace absl diff --git a/third_party/abseil-cpp/absl/types/span.h b/third_party/abseil-cpp/absl/types/span.h index d365f17d52..f781353c23 100644 --- a/third_party/abseil-cpp/absl/types/span.h +++ b/third_party/abseil-cpp/absl/types/span.h @@ -290,7 +290,8 @@ class Span { constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit) : Span(a, N) {} - // Explicit reference constructor for a mutable `Span` type + // Explicit reference constructor for a mutable `Span` type. Can be + // replaced with MakeSpan() to infer the type parameter. template , typename = EnableIfMutableView> explicit Span(V& v) noexcept // NOLINT(runtime/references) @@ -458,10 +459,20 @@ class Span { // Span::subspan() // - // Returns a `Span` starting at element `pos` and of length `len`, with - // proper bounds checking to ensure `len` does not exceed the ptr+size of the - // original array. (Spans whose `len` would point past the end of the array - // will throw a `std::out_of_range`.) + // Returns a `Span` starting at element `pos` and of length `len`. Both `pos` + // and `len` are of type `size_type` and thus non-negative. Parameter `pos` + // must be <= size(). Any `len` value that points past the end of the span + // will be trimmed to at most size() - `pos`. A default `len` value of `npos` + // ensures the returned subspan continues until the end of the span. + // + // Examples: + // + // std::vector vec = {10, 11, 12, 13}; + // absl::MakeSpan(vec).subspan(1, 2); // {11, 12} + // absl::MakeSpan(vec).subspan(2, 8); // {12, 13} + // absl::MakeSpan(vec).subspan(1); // {11, 12, 13} + // absl::MakeSpan(vec).subspan(4); // {} + // absl::MakeSpan(vec).subspan(5); // throws std::out_of_range constexpr Span subspan(size_type pos = 0, size_type len = npos) const { return (pos <= len_) ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len)) diff --git a/third_party/abseil-cpp/absl/types/variant.h b/third_party/abseil-cpp/absl/types/variant.h index 52a311e37d..7ae65abe0e 100644 --- a/third_party/abseil-cpp/absl/types/variant.h +++ b/third_party/abseil-cpp/absl/types/variant.h @@ -350,7 +350,7 @@ constexpr const variant_alternative_t>&& get( // get_if() // // Returns a pointer to the value currently stored within a given variant, if -// present, using either a unique alternative type amonst the variant's set of +// present, using either a unique alternative type amongst the variant's set of // alternative types, or the variant's index value. If such a value does not // exist, returns `nullptr`. // diff --git a/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc b/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc new file mode 100644 index 0000000000..377e4afac5 --- /dev/null +++ b/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc @@ -0,0 +1,519 @@ +// Copyright 2017 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 +// +// http://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/types/variant.h" + +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/internal/exception_safety_testing.h" +#include "absl/memory/memory.h" + +namespace absl { +namespace { + +using ::testing::MakeExceptionSafetyTester; +using ::testing::nothrow_guarantee; +using ::testing::strong_guarantee; +using ::testing::TestThrowingCtor; + +using Thrower = testing::ThrowingValue<>; +using CopyNothrow = testing::ThrowingValue; +using MoveNothrow = testing::ThrowingValue; +using ThrowingAlloc = testing::ThrowingAllocator; +using ThrowerVec = std::vector; +using ThrowingVariant = + absl::variant; + +struct ConversionException {}; + +template +struct ExceptionOnConversion { + operator T() const { // NOLINT + throw ConversionException(); + } +}; + +// Forces a variant into the valueless by exception state. +void ToValuelessByException(ThrowingVariant& v) { // NOLINT + try { + v.emplace(); + v.emplace(ExceptionOnConversion()); + } catch (ConversionException& /*e*/) { + // This space intentionally left blank. + } +} + +// Check that variant is still in a usable state after an exception is thrown. +testing::AssertionResult CheckInvariants(ThrowingVariant* v) { + using testing::AssertionFailure; + using testing::AssertionSuccess; + + // Try using the active alternative + if (absl::holds_alternative(*v)) { + auto& t = absl::get(*v); + t = Thrower{-100}; + if (t.Get() != -100) { + return AssertionFailure() << "Thrower should be assigned -100"; + } + } else if (absl::holds_alternative(*v)) { + auto& tv = absl::get(*v); + tv.clear(); + tv.emplace_back(-100); + if (tv.size() != 1 || tv[0].Get() != -100) { + return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}"; + } + } else if (absl::holds_alternative(*v)) { + auto& t = absl::get(*v); + t = CopyNothrow{-100}; + if (t.Get() != -100) { + return AssertionFailure() << "CopyNothrow should be assigned -100"; + } + } else if (absl::holds_alternative(*v)) { + auto& t = absl::get(*v); + t = MoveNothrow{-100}; + if (t.Get() != -100) { + return AssertionFailure() << "MoveNothrow should be assigned -100"; + } + } + + // Try making variant valueless_by_exception + if (!v->valueless_by_exception()) ToValuelessByException(*v); + if (!v->valueless_by_exception()) { + return AssertionFailure() << "Variant should be valueless_by_exception"; + } + try { + auto unused = absl::get(*v); + static_cast(unused); + return AssertionFailure() << "Variant should not contain Thrower"; + } catch (absl::bad_variant_access) { + } catch (...) { + return AssertionFailure() << "Unexpected exception throw from absl::get"; + } + + // Try using the variant + v->emplace(100); + if (!absl::holds_alternative(*v) || + absl::get(*v) != Thrower(100)) { + return AssertionFailure() << "Variant should contain Thrower(100)"; + } + v->emplace({Thrower(100)}); + if (!absl::holds_alternative(*v) || + absl::get(*v)[0] != Thrower(100)) { + return AssertionFailure() + << "Variant should contain ThrowerVec{Thrower(100)}"; + } + return AssertionSuccess(); +} + +Thrower ExpectedThrower() { return Thrower(42); } +ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; } +ThrowingVariant ValuelessByException() { + ThrowingVariant v; + ToValuelessByException(v); + return v; +} +ThrowingVariant WithThrower() { return Thrower(39); } +ThrowingVariant WithThrowerVec() { + return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)}; +} +ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); } +ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); } + +TEST(VariantExceptionSafetyTest, DefaultConstructor) { + TestThrowingCtor(); +} + +TEST(VariantExceptionSafetyTest, CopyConstructor) { + { + ThrowingVariant v(ExpectedThrower()); + TestThrowingCtor(v); + } + { + ThrowingVariant v(ExpectedThrowerVec()); + TestThrowingCtor(v); + } + { + ThrowingVariant v(ValuelessByException()); + TestThrowingCtor(v); + } +} + +TEST(VariantExceptionSafetyTest, MoveConstructor) { + { + ThrowingVariant v(ExpectedThrower()); + TestThrowingCtor(std::move(v)); + } + { + ThrowingVariant v(ExpectedThrowerVec()); + TestThrowingCtor(std::move(v)); + } + { + ThrowingVariant v(ValuelessByException()); + TestThrowingCtor(std::move(v)); + } +} + +TEST(VariantExceptionSafetyTest, ValueConstructor) { + TestThrowingCtor(ExpectedThrower()); + TestThrowingCtor(ExpectedThrowerVec()); +} + +TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) { + TestThrowingCtor(absl::in_place_type_t{}, + ExpectedThrower()); + TestThrowingCtor(absl::in_place_type_t{}, + ExpectedThrowerVec()); +} + +TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) { + TestThrowingCtor(absl::in_place_index_t<0>{}, + ExpectedThrower()); + TestThrowingCtor(absl::in_place_index_t<3>{}, + ExpectedThrowerVec()); +} + +TEST(VariantExceptionSafetyTest, CopyAssign) { + // variant& operator=(const variant& rhs); + // Let j be rhs.index() + { + // - neither *this nor rhs holds a value + const ThrowingVariant rhs = ValuelessByException(); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(ValuelessByException()) + .WithInvariants(nothrow_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } + { + // - *this holds a value but rhs does not + const ThrowingVariant rhs = ValuelessByException(); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(nothrow_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } + // - index() == j + { + const ThrowingVariant rhs(ExpectedThrower()); + auto tester = + MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); + EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test()); + EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); + } + { + const ThrowingVariant rhs(ExpectedThrowerVec()); + auto tester = + MakeExceptionSafetyTester() + .WithInitialValue(WithThrowerVec()) + .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); + EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test()); + EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); + } + // libstdc++ std::variant has bugs on copy assignment regarding exception + // safety. +#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) + // index() != j + // if is_nothrow_copy_constructible_v or + // !is_nothrow_move_constructible is true, equivalent to + // emplace(get(rhs)) + { + // is_nothrow_copy_constructible_v == true + // should not throw because emplace() invokes Tj's copy ctor + // which should not throw. + const ThrowingVariant rhs(CopyNothrow{}); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(nothrow_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } + { + // is_nothrow_copy_constructible == false && + // is_nothrow_move_constructible == false + // should provide basic guarantee because emplace() invokes Tj's copy ctor + // which may throw. + const ThrowingVariant rhs(ExpectedThrower()); + auto tester = + MakeExceptionSafetyTester() + .WithInitialValue(WithCopyNoThrow()) + .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); + EXPECT_TRUE(tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return lhs->valueless_by_exception(); + }) + .Test()); + EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); + } +#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) + { + // is_nothrow_copy_constructible_v == false && + // is_nothrow_move_constructible_v == true + // should provide strong guarantee because it is equivalent to + // operator=(variant(rhs)) which creates a temporary then invoke the move + // ctor which shouldn't throw. + const ThrowingVariant rhs(MoveNothrow{}); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(CheckInvariants, strong_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } +} + +TEST(VariantExceptionSafetyTest, MoveAssign) { + // variant& operator=(variant&& rhs); + // Let j be rhs.index() + { + // - neither *this nor rhs holds a value + ThrowingVariant rhs = ValuelessByException(); + + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(ValuelessByException()) + .WithInvariants(nothrow_guarantee) + .Test([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + })); + } + { + // - *this holds a value but rhs does not + ThrowingVariant rhs = ValuelessByException(); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(nothrow_guarantee) + .Test([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + })); + } + { + // - index() == j + // assign get(std::move(rhs)) to the value contained in *this. + // If an exception is thrown during call to Tj's move assignment, the state + // of the contained value is as defined by the exception safety guarantee of + // Tj's move assignment; index() will be j. + ThrowingVariant rhs(ExpectedThrower()); + size_t j = rhs.index(); + // Since Thrower's move assignment has basic guarantee, so should variant's. + auto tester = MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithOperation([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + }); + EXPECT_TRUE(tester + .WithInvariants( + CheckInvariants, + [j](ThrowingVariant* lhs) { return lhs->index() == j; }) + .Test()); + EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); + } + { + // - otherwise (index() != j), equivalent to + // emplace(get(std::move(rhs))) + // - If an exception is thrown during the call to Tj's move construction + // (with j being rhs.index()), the variant will hold no value. + ThrowingVariant rhs(CopyNothrow{}); + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return lhs->valueless_by_exception(); + }) + .Test([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + })); + } +} + +TEST(VariantExceptionSafetyTest, ValueAssign) { + // template variant& operator=(T&& t); + // Let Tj be the type that is selected by overload resolution to be assigned. + { + // If *this holds a Tj, assigns std::forward(t) to the value contained in + // *this. If an exception is thrown during the assignment of + // std::forward(t) to the value contained in *this, the state of the + // contained value and t are as defined by the exception safety guarantee of + // the assignment expression; valueless_by_exception() will be false. + // Since Thrower's copy/move assignment has basic guarantee, so should + // variant's. + Thrower rhs = ExpectedThrower(); + // copy assign + auto copy_tester = + MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; }); + EXPECT_TRUE(copy_tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return !lhs->valueless_by_exception(); + }) + .Test()); + EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test()); + // move assign + auto move_tester = MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithOperation([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + }); + EXPECT_TRUE(move_tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return !lhs->valueless_by_exception(); + }) + .Test()); + + EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test()); + } + // Otherwise (*this holds something else), if is_nothrow_constructible_v || !is_nothrow_move_constructible_v is true, equivalent to + // emplace(std::forward(t)). + // We simplify the test by letting T = `const Tj&` or `Tj&&`, so we can reuse + // the CopyNothrow and MoveNothrow types. + + // if is_nothrow_constructible_v + // (i.e. is_nothrow_copy/move_constructible_v) is true, emplace() just + // invokes the copy/move constructor and it should not throw. + { + const CopyNothrow rhs; + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(nothrow_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } + { + MoveNothrow rhs; + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(nothrow_guarantee) + .Test([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + })); + } + // if is_nothrow_constructible_v == false && + // is_nothrow_move_constructible == false + // emplace() invokes the copy/move constructor which may throw so it should + // provide basic guarantee and variant object might not hold a value. + { + Thrower rhs = ExpectedThrower(); + // copy + auto copy_tester = + MakeExceptionSafetyTester() + .WithInitialValue(WithCopyNoThrow()) + .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); + EXPECT_TRUE(copy_tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return lhs->valueless_by_exception(); + }) + .Test()); + EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test()); + // move + auto move_tester = MakeExceptionSafetyTester() + .WithInitialValue(WithCopyNoThrow()) + .WithOperation([rhs](ThrowingVariant* lhs) mutable { + *lhs = std::move(rhs); + }); + EXPECT_TRUE(move_tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* lhs) { + return lhs->valueless_by_exception(); + }) + .Test()); + EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test()); + } + // Otherwise (if is_nothrow_constructible_v == false && + // is_nothrow_move_constructible == true), + // equivalent to operator=(variant(std::forward(t))) + // This should have strong guarantee because it creates a temporary variant + // and operator=(variant&&) invokes Tj's move ctor which doesn't throw. + // libstdc++ std::variant has bugs on conversion assignment regarding + // exception safety. +#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) + { + MoveNothrow rhs; + EXPECT_TRUE(MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(CheckInvariants, strong_guarantee) + .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); + } +#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) +} + +TEST(VariantExceptionSafetyTest, Emplace) { + // If an exception during the initialization of the contained value, the + // variant might not hold a value. The standard requires emplace() to provide + // only basic guarantee. + { + Thrower args = ExpectedThrower(); + auto tester = MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithOperation([&args](ThrowingVariant* v) { + v->emplace(args); + }); + EXPECT_TRUE(tester + .WithInvariants(CheckInvariants, + [](ThrowingVariant* v) { + return v->valueless_by_exception(); + }) + .Test()); + EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); + } +} + +TEST(VariantExceptionSafetyTest, Swap) { + // if both are valueless_by_exception(), no effect + { + ThrowingVariant rhs = ValuelessByException(); + EXPECT_TRUE( + MakeExceptionSafetyTester() + .WithInitialValue(ValuelessByException()) + .WithInvariants(nothrow_guarantee) + .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); })); + } + // if index() == rhs.index(), calls swap(get(*this), get(rhs)) + // where i is index(). + { + ThrowingVariant rhs = ExpectedThrower(); + EXPECT_TRUE( + MakeExceptionSafetyTester() + .WithInitialValue(WithThrower()) + .WithInvariants(CheckInvariants) + .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); })); + } + // Otherwise, exchanges the value of rhs and *this. The exception safety + // involves variant in moved-from state which is not specified in the + // standard, and since swap is 3-step it's impossible for it to provide a + // overall strong guarantee. So, we are only checking basic guarantee here. + { + ThrowingVariant rhs = ExpectedThrower(); + EXPECT_TRUE( + MakeExceptionSafetyTester() + .WithInitialValue(WithCopyNoThrow()) + .WithInvariants(CheckInvariants) + .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); })); + } + { + ThrowingVariant rhs = ExpectedThrower(); + EXPECT_TRUE( + MakeExceptionSafetyTester() + .WithInitialValue(WithCopyNoThrow()) + .WithInvariants(CheckInvariants) + .Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); })); + } +} + +} // namespace +} // namespace absl diff --git a/third_party/abseil-cpp/absl/types/variant_test.cc b/third_party/abseil-cpp/absl/types/variant_test.cc index c4676c10c6..262bd9446c 100644 --- a/third_party/abseil-cpp/absl/types/variant_test.cc +++ b/third_party/abseil-cpp/absl/types/variant_test.cc @@ -119,19 +119,9 @@ struct ConversionException {}; template struct ExceptionOnConversion { - // Suppress MSVC 2017 warning "noreturn function has a non-void return type". -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4646) -#endif // _MSC_VER - - [[noreturn]] operator T() const { // NOLINT(runtime/explicit) + operator T() const { // NOLINT(runtime/explicit) throw ConversionException(); } - -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER }; // Forces a variant into the valueless by exception state. diff --git a/third_party/abseil-cpp/absl/utility/CMakeLists.txt b/third_party/abseil-cpp/absl/utility/CMakeLists.txt index df21b85b34..dc3a631905 100644 --- a/third_party/abseil-cpp/absl/utility/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/utility/CMakeLists.txt @@ -22,6 +22,8 @@ list(APPEND UTILITY_PUBLIC_HEADERS absl_header_library( TARGET absl_utility + PUBLIC_LIBRARIES + absl::base EXPORT_NAME utility ) @@ -33,7 +35,12 @@ absl_header_library( # test utility_test set(UTILITY_TEST_SRC "utility_test.cc") -set(UTILITY_TEST_PUBLIC_LIBRARIES absl::utility) +set(UTILITY_TEST_PUBLIC_LIBRARIES + absl::base + absl::memory + absl::strings + absl::utility +) absl_test( TARGET diff --git a/third_party/abseil-cpp/absl/utility/utility.h b/third_party/abseil-cpp/absl/utility/utility.h index 5b9b84e05d..d73602c47d 100644 --- a/third_party/abseil-cpp/absl/utility/utility.h +++ b/third_party/abseil-cpp/absl/utility/utility.h @@ -24,6 +24,7 @@ // * make_index_sequence == std::make_index_sequence // * index_sequence_for == std::index_sequence_for // * apply == std::apply +// * exchange == std::exchange // // This header file also provides the tag types `in_place_t`, `in_place_type_t`, // and `in_place_index_t`, as well as the constant `in_place`, and @@ -264,6 +265,27 @@ auto apply(Functor&& functor, Tuple&& t) absl::make_index_sequence::type>::value>{}); } + +// exchange +// +// Replaces the value of `obj` with `new_value` and returns the old value of +// `obj`. `absl::exchange` is designed to be a drop-in replacement for C++14's +// `std::exchange`. +// +// Example: +// +// Foo& operator=(Foo&& other) { +// ptr1_ = absl::exchange(other.ptr1_, nullptr); +// int1_ = absl::exchange(other.int1_, -1); +// return *this; +// } +template +T exchange(T& obj, U&& new_value) { + T old_value = absl::move(obj); + obj = absl::forward(new_value); + return old_value; +} + } // namespace absl #endif // ABSL_UTILITY_UTILITY_H_ diff --git a/third_party/abseil-cpp/absl/utility/utility_test.cc b/third_party/abseil-cpp/absl/utility/utility_test.cc index 342165ed52..3c447b20bb 100644 --- a/third_party/abseil-cpp/absl/utility/utility_test.cc +++ b/third_party/abseil-cpp/absl/utility/utility_test.cc @@ -333,5 +333,13 @@ TEST(ApplyTest, FlipFlop) { EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj))); } +TEST(ExchangeTest, MoveOnly) { + auto a = Factory(1); + EXPECT_EQ(1, *a); + auto b = absl::exchange(a, Factory(2)); + EXPECT_EQ(2, *a); + EXPECT_EQ(1, *b); +} + } // namespace diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp index 592e50db89..1b6b8c04a4 100644 --- a/third_party/closure_compiler/compiled_resources2.gyp +++ b/third_party/closure_compiler/compiled_resources2.gyp @@ -22,7 +22,6 @@ '<(DEPTH)/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*', - '<(DEPTH)/chrome/browser/resources/ntp4/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/cr_components/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*', diff --git a/third_party/closure_compiler/externs/OWNERS b/third_party/closure_compiler/externs/OWNERS index 33acaf17a3..8d19f08198 100644 --- a/third_party/closure_compiler/externs/OWNERS +++ b/third_party/closure_compiler/externs/OWNERS @@ -1,3 +1,6 @@ michaelpg@chromium.org rdevlin.cronin@chromium.org stevenjb@chromium.org + +per-file accessibility_private.js=file://ui/accessibility/OWNERS +per-file automation.js=file://ui/accessibility/OWNERS diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js index 1bb06e0733..ecbf46555e 100644 --- a/third_party/closure_compiler/externs/automation.js +++ b/third_party/closure_compiler/externs/automation.js @@ -285,6 +285,7 @@ chrome.automation.StateType = { */ chrome.automation.ActionType = { BLUR: 'blur', + CLEAR_ACCESSIBILITY_FOCUS: 'clearAccessibilityFocus', CUSTOM_ACTION: 'customAction', DECREMENT: 'decrement', DO_DEFAULT: 'doDefault', @@ -302,6 +303,7 @@ chrome.automation.ActionType = { SCROLL_TO_MAKE_VISIBLE: 'scrollToMakeVisible', SCROLL_TO_POINT: 'scrollToPoint', SCROLL_UP: 'scrollUp', + SET_ACCESSIBILITY_FOCUS: 'setAccessibilityFocus', SET_SCROLL_OFFSET: 'setScrollOffset', SET_SELECTION: 'setSelection', SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT: 'setSequentialFocusNavigationStartingPoint', diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium index 853f7eb235..53425f0421 100644 --- a/third_party/opus/README.chromium +++ b/third_party/opus/README.chromium @@ -16,3 +16,5 @@ Local changes: * set 'x' flags: "chmod 750 win32/genversion.bat" * Apply https://git.xiph.org/?p=opus.git;a=commitdiff;h=46560534fcb5710a894a341c2f9526db58fd7087#patch1 * Apply https://github.com/xiph/opus/pull/73 +* Apply https://github.com/xiph/opus/pull/87 +* Make sure HB_gain is not NaN in an attempt to fix chromium:826914 diff --git a/third_party/opus/src/silk/API.h b/third_party/opus/src/silk/API.h index 0131acbb08..4d90ff9aa3 100644 --- a/third_party/opus/src/silk/API.h +++ b/third_party/opus/src/silk/API.h @@ -80,7 +80,8 @@ opus_int silk_Encode( /* O Returns error co opus_int nSamplesIn, /* I Number of samples in input vector */ ec_enc *psRangeEnc, /* I/O Compressor data structure */ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ - const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + int activity /* I Decision of Opus voice activity detector */ ); /****************************************/ diff --git a/third_party/opus/src/silk/define.h b/third_party/opus/src/silk/define.h index 1286048e7e..22fd720b97 100644 --- a/third_party/opus/src/silk/define.h +++ b/third_party/opus/src/silk/define.h @@ -58,6 +58,11 @@ extern "C" #define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ #define DTX_ACTIVITY_THRESHOLD 0.1f +/* VAD decision */ +#define VAD_NO_DECISION -1 +#define VAD_NO_ACTIVITY 0 +#define VAD_ACTIVITY 1 + /* Maximum sampling frequency */ #define MAX_FS_KHZ 16 #define MAX_API_FS_KHZ 48 diff --git a/third_party/opus/src/silk/enc_API.c b/third_party/opus/src/silk/enc_API.c index 701c29050c..0a62a3c1d7 100644 --- a/third_party/opus/src/silk/enc_API.c +++ b/third_party/opus/src/silk/enc_API.c @@ -144,7 +144,8 @@ opus_int silk_Encode( /* O Returns error co opus_int nSamplesIn, /* I Number of samples in input vector */ ec_enc *psRangeEnc, /* I/O Compressor data structure */ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ - const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + opus_int activity /* I Decision of Opus voice activity detector */ ) { opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; @@ -425,7 +426,7 @@ opus_int silk_Encode( /* O Returns error co psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; } - silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] ); + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity ); } else { psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; } @@ -440,7 +441,7 @@ opus_int silk_Encode( /* O Returns error co silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); } - silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] ); + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity ); /* Encode */ for( n = 0; n < encControl->nChannelsInternal; n++ ) { diff --git a/third_party/opus/src/silk/fixed/encode_frame_FIX.c b/third_party/opus/src/silk/fixed/encode_frame_FIX.c index 0efa9e6339..f6ee813b97 100644 --- a/third_party/opus/src/silk/fixed/encode_frame_FIX.c +++ b/third_party/opus/src/silk/fixed/encode_frame_FIX.c @@ -43,18 +43,25 @@ static OPUS_INLINE void silk_LBRR_encode_FIX( ); void silk_encode_do_VAD_FIX( - silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ ) { + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + /****************************/ /* Voice Activity Detection */ /****************************/ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } /**************************************************/ /* Convert speech activity into VAD and DTX flags */ /**************************************************/ - if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; psEnc->sCmn.noSpeechCounter++; if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { diff --git a/third_party/opus/src/silk/fixed/main_FIX.h b/third_party/opus/src/silk/fixed/main_FIX.h index 780afa39c3..6d2112e511 100644 --- a/third_party/opus/src/silk/fixed/main_FIX.h +++ b/third_party/opus/src/silk/fixed/main_FIX.h @@ -66,7 +66,8 @@ void silk_HP_variable_cutoff( /* Encoder main function */ void silk_encode_do_VAD_FIX( - silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ ); /* Encoder main function */ diff --git a/third_party/opus/src/silk/float/encode_frame_FLP.c b/third_party/opus/src/silk/float/encode_frame_FLP.c index 5db85c769f..49956a2d75 100644 --- a/third_party/opus/src/silk/float/encode_frame_FLP.c +++ b/third_party/opus/src/silk/float/encode_frame_FLP.c @@ -42,18 +42,25 @@ static OPUS_INLINE void silk_LBRR_encode_FLP( ); void silk_encode_do_VAD_FLP( - silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ ) { + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + /****************************/ /* Voice Activity Detection */ /****************************/ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } /**************************************************/ /* Convert speech activity into VAD and DTX flags */ /**************************************************/ - if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; psEnc->sCmn.noSpeechCounter++; if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { diff --git a/third_party/opus/src/silk/float/main_FLP.h b/third_party/opus/src/silk/float/main_FLP.h index f47fc93bec..5dc0ccf4a4 100644 --- a/third_party/opus/src/silk/float/main_FLP.h +++ b/third_party/opus/src/silk/float/main_FLP.h @@ -56,7 +56,8 @@ void silk_HP_variable_cutoff( /* Encoder main function */ void silk_encode_do_VAD_FLP( - silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ ); /* Encoder main function */ diff --git a/third_party/opus/src/src/opus_encoder.c b/third_party/opus/src/src/opus_encoder.c index cd37fcdfe4..2149c20b41 100644 --- a/third_party/opus/src/src/opus_encoder.c +++ b/third_party/opus/src/src/opus_encoder.c @@ -1661,6 +1661,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_CELT_ONLY) { opus_int32 total_bitRate, celt_rate; + opus_int activity; #ifdef FIXED_POINT const opus_int16 *pcm_silk; #else @@ -1668,6 +1669,14 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ ALLOC(pcm_silk, st->channels*frame_size, opus_int16); #endif + activity = VAD_NO_DECISION; +#ifndef DISABLE_FLOAT_API + if( analysis_info.valid ) { + /* Inform SILK about the Opus VAD decision */ + activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD ); + } +#endif + /* Distribute bits between SILK and CELT */ total_bitRate = 8 * bytes_target * frame_rate; if( st->mode == MODE_HYBRID ) { @@ -1679,6 +1688,12 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* Increasingly attenuate high band when it gets allocated fewer bits */ celt_rate = total_bitRate - st->silk_mode.bitRate; HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1); +#ifndef FIXED_POINT + /* Sanity check of high band gain */ + if (celt_isnan(HB_gain)) { + HB_gain = Q15ONE; + } +#endif } } else { /* SILK gets all bits */ @@ -1813,7 +1828,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ for (i=0;iencoder_buffer*st->channels;i++) pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); #endif - silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 ); + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1, activity ); } #ifdef FIXED_POINT @@ -1822,7 +1837,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ for (i=0;ichannels;i++) pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]); #endif - ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity ); if( ret ) { /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ /* Handle error */