[libc++] Allow enabling assertions when back-deploying
authorLouis Dionne <ldionne.2@gmail.com>
Thu, 4 Aug 2022 19:25:48 +0000 (15:25 -0400)
committerLouis Dionne <ldionne.2@gmail.com>
Mon, 8 Aug 2022 12:43:34 +0000 (08:43 -0400)
When back-deploying to older platforms, we can still provide assertions,
but we might not be able to provide a great implementation for the verbose
handler. Instead, we can just call ::abort().

Differential Revision: https://reviews.llvm.org/D131199

libcxx/docs/UsingLibcxx.rst
libcxx/include/__availability
libcxx/include/__verbose_abort
libcxx/test/libcxx/assertions/default_verbose_abort.availability.verify.cpp [deleted file]
libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp
libcxx/test/libcxx/assertions/single_expression.sh.cpp
libcxx/utils/ci/buildkite-pipeline.yml
libcxx/utils/ci/run-buildbot

index c0d4cee..41d1737 100644 (file)
@@ -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
 ===========================
 
index d64bde1..72ff663 100644 (file)
     // 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__)
 
         __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...
 #   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
index 489047c..822df21 100644 (file)
 #  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 (file)
index 932fc24..0000000
+++ /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 <version> // any header would work
-
-void f() {
-  _LIBCPP_ASSERT(true, "message"); // expected-error {{'__libcpp_verbose_abort' is unavailable}}
-}
index 1b4e361..79d26c8 100644 (file)
 
 // 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 <csignal>
 #include <cstdlib>
 
index e659732..53ad13b 100644 (file)
@@ -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 <uchar.h> seems to be broken on AIX, which trips up this test.
 // XFAIL: LIBCXX-AIX-FIXME
 
index fb66110..60847f3 100644 (file)
 // 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 <cassert>
 
index ac199b0..a4d6f72 100644 (file)
@@ -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"
index c0f6cd0..2cdbf8b 100755 (executable)
@@ -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