diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst index c0d4cee0b6c327..41d17378a2c3a9 100644 --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -155,11 +155,14 @@ value for ``_LIBCPP_ENABLE_ASSERTIONS`` (if any) will usually be respected. When an assertion fails, the program is aborted through a special verbose termination function. The library provides a default function that prints an error message and calls ``std::abort()``. Note that this function is provided by the static or shared library, so it is only available when deploying -to a platform where the compiled library is sufficiently recent. However, users can also override that -function with their own, which can be useful to provide custom behavior, or when deploying to older -platforms where the default function isn't available. +to a platform where the compiled library is sufficiently recent. On older platforms, the program will +terminate in an unspecified unsuccessful manner, but the quality of diagnostics won't be great. +However, users can also override that function with their own, which can be useful to either provide +custom behavior or when deploying to an older platform where the default function isn't available. -Replacing the default verbose termination function is done by defining the following function: +Replacing the default verbose termination function is done by defining the +``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro in all translation units of your program +and defining the following function in exactly one translation unit: .. code-block:: cpp @@ -198,20 +201,6 @@ Furthermore, exceptions should not be thrown from the function. Indeed, many fun library are ``noexcept``, and any exception thrown from the termination function will result in ``std::terminate`` being called. -Back-deploying with a custom verbose termination function ---------------------------------------------------------- -When deploying to an older platform that does not provide a default verbose termination function, -the compiler will diagnose the usage of ``std::__libcpp_verbose_abort`` with an error. This is done -to avoid the load-time error that would otherwise happen if the code was being deployed on older -systems. - -If you are providing a custom verbose termination function, this error is effectively a false positive. -To let the library know that you are providing a custom function in back-deployment scenarios, you must -define the ``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro, and the library will assume that -you are providing your own definition. If no definition is provided and the code is back-deployed to an older -platform, it will fail to load when the dynamic linker fails to find a definition of the function, so you -should only remove the guard rails if you really mean it! - Libc++ Configuration Macros =========================== diff --git a/libcxx/include/__availability b/libcxx/include/__availability index d64bde1253382e..72ff663334d36c 100644 --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -166,11 +166,11 @@ // user has provided their own). // // Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED - // to the compiler to tell the library to ignore the fact that the - // default function isn't available on their deployment target. Note that - // defining this macro but failing to define a custom function will lead to - // a load-time error on back-deployment targets, so it should be avoided. -# define _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT + // to the compiler to tell the library not to define its own verbose abort. + // Note that defining this macro but failing to define a custom function + // will lead to a load-time error on back-deployment targets, so it should + // be avoided. +// # define _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY #elif defined(__APPLE__) @@ -271,8 +271,8 @@ __attribute__((unavailable)) # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format -# define _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT \ - __attribute__((unavailable)) +# define _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY + #else // ...New vendors can add availability markup here... @@ -296,14 +296,4 @@ # define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS #endif -// Define the special verbose termination function availability attribute, which can be silenced by -// users if they provide their own custom function. The rest of the code should not use the -// *_DEFAULT_* macro directly, since that would make it ignore the fact that the user provided -// a custom function. -#if defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED) -# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT /* nothing */ -#else -# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT -#endif - #endif // _LIBCPP___AVAILABILITY diff --git a/libcxx/include/__verbose_abort b/libcxx/include/__verbose_abort index 489047c74cc4d7..822df215039ae7 100644 --- a/libcxx/include/__verbose_abort +++ b/libcxx/include/__verbose_abort @@ -17,11 +17,34 @@ # pragma GCC system_header #endif +// Provide a default implementation of __libcpp_verbose_abort if we know that neither the built +// library not the user is providing one. Otherwise, just declare it and use the one from the +// built library or the one provided by the user. +// +// We can't provide a great implementation because it needs to be pretty much +// dependency-free (this is included everywhere else in the library). +#if defined(_LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY) && !defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED) + +extern "C" void abort(); + _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) +_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) _LIBCPP_HIDE_FROM_ABI inline +void __libcpp_verbose_abort(const char *, ...) { + ::abort(); +} + +_LIBCPP_END_NAMESPACE_STD + +#else + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) void __libcpp_verbose_abort(const char *__format, ...); _LIBCPP_END_NAMESPACE_STD +#endif + #endif // _LIBCPP___VERBOSE_ABORT diff --git a/libcxx/test/libcxx/assertions/default_verbose_abort.availability.verify.cpp b/libcxx/test/libcxx/assertions/default_verbose_abort.availability.verify.cpp deleted file mode 100644 index 932fc243543974..00000000000000 --- a/libcxx/test/libcxx/assertions/default_verbose_abort.availability.verify.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// Make sure that we diagnose any usage of the default verbose termination function -// on a platform that doesn't support it at compile-time. - -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 - -// REQUIRES: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}} - -#include // any header would work - -void f() { - _LIBCPP_ASSERT(true, "message"); // expected-error {{'__libcpp_verbose_abort' is unavailable}} -} diff --git a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp index 1b4e3615a7be39..79d26c8c484762 100644 --- a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp +++ b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp @@ -10,10 +10,6 @@ // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 -// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime -// failures when back-deploying. -// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} - #include #include diff --git a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp index e659732f743f9b..53ad13b4d59baa 100644 --- a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp +++ b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp @@ -8,10 +8,6 @@ // Test that all public C++ headers define the verbose termination function. -// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime -// failures when back-deploying. -// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} - // The system-provided seems to be broken on AIX, which trips up this test. // XFAIL: LIBCXX-AIX-FIXME diff --git a/libcxx/test/libcxx/assertions/single_expression.sh.cpp b/libcxx/test/libcxx/assertions/single_expression.sh.cpp index fb661103b6de63..60847f3eef74fc 100644 --- a/libcxx/test/libcxx/assertions/single_expression.sh.cpp +++ b/libcxx/test/libcxx/assertions/single_expression.sh.cpp @@ -18,10 +18,6 @@ // RUN: %{build} -Wno-macro-redefined -D_LIBCPP_ENABLE_ASSERTIONS=0 -D_LIBCPP_ASSERTIONS_DISABLE_ASSUME // RUN: %{run} -// We flag uses of the assertion handler in older dylibs at compile-time to avoid runtime -// failures when back-deploying. -// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} - #include <__assert> #include diff --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml index ac199b05f5f2fc..a4d6f729004077 100644 --- a/libcxx/utils/ci/buildkite-pipeline.yml +++ b/libcxx/utils/ci/buildkite-pipeline.yml @@ -725,6 +725,20 @@ steps: limit: 2 timeout_in_minutes: 120 + - label: "Apple back-deployment with assertions enabled" + command: "libcxx/utils/ci/run-buildbot apple-system-backdeployment-assertions-11.0" + artifact_paths: + - "**/test-results.xml" + - "**/*.abilist" + agents: + queue: "libcxx-builders" + os: "macos" + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + timeout_in_minutes: 120 + - group: "ARM" steps: - label: "AArch64" diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot index c0f6cd0ae9d128..2cdbf8b9abe73c 100755 --- a/libcxx/utils/ci/run-buildbot +++ b/libcxx/utils/ci/run-buildbot @@ -385,6 +385,48 @@ apple-system) # TODO: It would be better to run the tests against the fake-installed version of libc++ instead xcrun --sdk macosx ninja -vC "${BUILD_DIR}/${arch}" check-cxx check-cxxabi check-cxx-abilist ;; +apple-system-backdeployment-assertions-*) + clean + + if [[ "${OSX_ROOTS}" == "" ]]; then + echo "--- Downloading previous macOS dylibs" + PREVIOUS_DYLIBS_URL="https://dl.dropboxusercontent.com/s/gmcfxwgl9f9n6pu/libcxx-roots.tar.gz" + OSX_ROOTS="${BUILD_DIR}/macos-roots" + mkdir -p "${OSX_ROOTS}" + curl "${PREVIOUS_DYLIBS_URL}" | tar -xz --strip-components=1 -C "${OSX_ROOTS}" + fi + + DEPLOYMENT_TARGET="${BUILDER#apple-system-backdeployment-assertions-}" + + # TODO: On Apple platforms, we never produce libc++abi.1.dylib or libunwind.1.dylib, + # only libc++abi.dylib and libunwind.dylib. Fix that in the build so that the + # tests stop searching for @rpath/libc++abi.1.dylib and @rpath/libunwind.1.dylib. + cp "${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}/libc++abi.dylib" \ + "${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}/libc++abi.1.dylib" + cp "${OSX_ROOTS}/macOS/libunwind/${DEPLOYMENT_TARGET}/libunwind.dylib" \ + "${OSX_ROOTS}/macOS/libunwind/${DEPLOYMENT_TARGET}/libunwind.1.dylib" + + arch="$(uname -m)" + PARAMS="target_triple=${arch}-apple-macosx${DEPLOYMENT_TARGET}" + PARAMS+=";cxx_runtime_root=${OSX_ROOTS}/macOS/libc++/${DEPLOYMENT_TARGET}" + PARAMS+=";abi_runtime_root=${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}" + PARAMS+=";unwind_runtime_root=${OSX_ROOTS}/macOS/libunwind/${DEPLOYMENT_TARGET}" + PARAMS+=";use_system_cxx_lib=True" + PARAMS+=";enable_assertions=True" + # TODO: Enable experimental features during back-deployment -- right now some of the availability + # annotations are incorrect, leading to test failures that could be avoided. + PARAMS+=";enable_experimental=False" + + generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Apple.cmake" \ + -DLIBCXX_TEST_CONFIG="apple-libc++-backdeployment.cfg.in" \ + -DLIBCXXABI_TEST_CONFIG="apple-libc++abi-backdeployment.cfg.in" \ + -DLIBUNWIND_TEST_CONFIG="apple-libunwind-backdeployment.cfg.in" \ + -DLIBCXX_TEST_PARAMS="${PARAMS}" \ + -DLIBCXXABI_TEST_PARAMS="${PARAMS}" \ + -DLIBUNWIND_TEST_PARAMS="${PARAMS}" + + check-runtimes +;; apple-system-backdeployment-*) clean