diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index 75cb63222da35..a4046da847dd8 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -69,6 +69,13 @@ if (NOT "${LIBCXX_HARDENING_MODE}" IN_LIST LIBCXX_SUPPORTED_HARDENING_MODES) message(FATAL_ERROR "Unsupported hardening mode: '${LIBCXX_HARDENING_MODE}'. Supported values are ${LIBCXX_SUPPORTED_HARDENING_MODES}.") endif() +set(LIBCXX_ASSERTION_HANDLER_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/vendor/llvm/default_assertion_handler.in" + CACHE STRING + "Specify the path to a header that contains a custom implementation of the + assertion handler that gets invoked when a hardening assertion fails. If + provided, this header will be included by the library, replacing the + default assertion handler.") option(LIBCXX_ENABLE_RANDOM_DEVICE "Whether to include support for std::random_device in the library. Disabling this can be useful when building the library for platforms that don't have diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst index 0b4d420528651..dedf0a516bbb7 100644 --- a/libcxx/docs/BuildingLibcxx.rst +++ b/libcxx/docs/BuildingLibcxx.rst @@ -409,6 +409,15 @@ libc++ Feature Options Use the specified GCC toolchain and standard library when building the native stdlib benchmark tests. +.. option:: LIBCXX_ASSERTION_HANDLER_FILE:PATH + + **Default**:: ``"${CMAKE_CURRENT_SOURCE_DIR}/vendor/llvm/default_assertion_handler.in"`` + + Specify the path to a header that contains a custom implementation of the + assertion handler that gets invoked when a hardening assertion fails. If + provided, this header will be included by the library, replacing the + default assertion handler. + libc++ ABI Feature Options -------------------------- @@ -473,6 +482,43 @@ LLVM-specific options others. +.. _assertion-handler: + +Overriding the default assertion handler +========================================== + +When the library wants to terminate due to an unforeseen condition (such as +a hardening assertion failure), 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. On older +platforms, the program will terminate in an unspecified unsuccessful manner, but +the quality of diagnostics won't be great. + +However, vendors can also override that mechanism at CMake configuration time. +When a hardening assertion fails, the library invokes the +``_LIBCPP_ASSERTION_HANDLER`` macro. A vendor may provide a header that contains +a custom definition of this macro and specify the path to the header via the +``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable. If provided, this header will +be included by the library and replace the default implementation. The header +must not include any standard library headers (directly or transitively) because +doing so will almost always create a circular dependency. The +``_LIBCPP_ASSERTION_HANDLER(message)`` macro takes a single parameter that +contains an error message explaining the hardening failure and some details +about the source location that triggered it. + +When a hardening assertion fails, it means that the program is about to invoke +library undefined behavior. For this reason, the custom assertion handler is +generally expected to terminate the program. If a custom assertion handler +decides to avoid doing so (e.g. it chooses to log and continue instead), it does +so at its own risk -- this approach should only be used in non-production builds +and with an understanding of potential consequences. Furthermore, the custom +assertion handler should not throw any exceptions as it may be invoked from +standard library functions that are marked ``noexcept`` (so throwing will result +in ``std::terminate`` being called). + + Using Alternate ABI libraries ============================= diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index 882f53b8d9f83..da190aa8d3f64 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -107,6 +107,10 @@ Deprecations and Removals macro is provided to restore the previous behavior, and it will be supported in the LLVM 18 release only. In LLVM 19 and beyond, ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT`` will not be honored anymore. +- The only supported way to customize the assertion handler that gets invoked when a hardening assertion fails + is now by setting the ``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable and providing a custom header. See + the documentation on overriding the default assertion handler for details. + - The ``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro is not honored anymore in LLVM 18. Please see the updated documentation about the hardening modes in libc++ and in particular the ``_LIBCPP_VERBOSE_ABORT`` macro for details. diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst index e1bbf39b9634a..917f86b9aef97 100644 --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -146,70 +146,6 @@ IWYU, you should run the tool like so: If you would prefer to not use that flag, then you can replace ``/path/to/include-what-you-use/share/libcxx.imp`` file with the libc++-provided ``libcxx.imp`` file. -.. _termination-handler: - -Overriding the default termination handler -========================================== - -When the library wants to terminate due to an unforeseen condition (such as a hardening assertion -failure), 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. 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 mechanism at two different levels. First, the mechanism can be -overridden at compile time by defining the ``_LIBCPP_VERBOSE_ABORT(format, args...)`` variadic macro. -When that macro is defined, it will be called with a format string as the first argument, followed by -a series of arguments to format using printf-style formatting. Compile-time customization may be -useful to get precise control over code generation, however it is also inconvenient to use in -some cases. Indeed, compile-time customization of the verbose termination function requires that all -translation units be compiled with a consistent definition for ``_LIBCPP_VERBOSE_ABORT`` to avoid ODR -violations, which can add complexity in the build system of users. - -Otherwise, if compile-time customization is not necessary, link-time customization of the handler is also -possible, similarly to how replacing ``operator new`` works. This mechanism trades off fine-grained control -over the call site where the termination is initiated in exchange for better ergonomics. Link-time -customization is done by simply defining the following function in exactly one translation unit of your -program: - -.. code-block:: cpp - - void __libcpp_verbose_abort(char const* format, ...) - -This mechanism is similar to how one can replace the default definition of ``operator new`` -and ``operator delete``. For example: - -.. code-block:: cpp - - // In HelloWorldHandler.cpp - #include // must include any libc++ header before defining the function (C compatibility headers excluded) - - void std::__libcpp_verbose_abort(char const* format, ...) { - std::va_list list; - va_start(list, format); - std::vfprintf(stderr, format, list); - va_end(list); - - std::abort(); - } - - // In HelloWorld.cpp - #include - - int main() { - std::vector v; - int& x = v[0]; // Your termination function will be called here if hardening is enabled. - } - -Also note that the verbose termination function should never return. Since assertions in libc++ -catch undefined behavior, your code will proceed with undefined behavior if your function is called -and does return. - -Furthermore, exceptions should not be thrown from the function. Indeed, many functions in the -library are ``noexcept``, and any exception thrown from the termination function will result -in ``std::terminate`` being called. - Libc++ Configuration Macros =========================== diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 0fe3ab44d2466..9fdf978a89d7e 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -1020,9 +1020,11 @@ endforeach() configure_file("__config_site.in" "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}/__config_site" @ONLY) configure_file("module.modulemap.in" "${LIBCXX_GENERATED_INCLUDE_DIR}/module.modulemap" @ONLY) +configure_file("${LIBCXX_ASSERTION_HANDLER_FILE}" "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler" COPYONLY) set(_all_includes "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}/__config_site" - "${LIBCXX_GENERATED_INCLUDE_DIR}/module.modulemap") + "${LIBCXX_GENERATED_INCLUDE_DIR}/module.modulemap" + "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler") foreach(f ${files}) set(src "${CMAKE_CURRENT_SOURCE_DIR}/${f}") set(dst "${LIBCXX_GENERATED_INCLUDE_DIR}/${f}") @@ -1059,6 +1061,12 @@ if (LIBCXX_INSTALL_HEADERS) PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT cxx-headers) + # Install the generated __assertion_handler file to the generic include dir. + install(FILES "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler" + DESTINATION "${LIBCXX_INSTALL_INCLUDE_DIR}" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + COMPONENT cxx-headers) + # Install the generated modulemap file to the generic include dir. install(FILES "${LIBCXX_GENERATED_INCLUDE_DIR}/module.modulemap" DESTINATION "${LIBCXX_INSTALL_INCLUDE_DIR}" diff --git a/libcxx/include/__assert b/libcxx/include/__assert index d4af7e6c7192a..eb862b5369b25 100644 --- a/libcxx/include/__assert +++ b/libcxx/include/__assert @@ -10,8 +10,8 @@ #ifndef _LIBCPP___ASSERT #define _LIBCPP___ASSERT +#include <__assertion_handler> // Note: this include is generated by CMake and is potentially vendor-provided. #include <__config> -#include <__verbose_abort> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,8 +20,8 @@ #define _LIBCPP_ASSERT(expression, message) \ (__builtin_expect(static_cast(expression), 1) \ ? (void)0 \ - : _LIBCPP_VERBOSE_ABORT( \ - "%s:%d: assertion %s failed: %s\n", __builtin_FILE(), __builtin_LINE(), #expression, message)) + : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \ + expression) " failed: " message "\n")) // TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add // assumptions without a clear optimization intent, disable that to avoid worsening the code generation. diff --git a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp index be08159d561bb..a40ae84fa8e85 100644 --- a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp +++ b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp @@ -10,8 +10,8 @@ // This test ensures that enabling assertions with the legacy `_LIBCPP_ENABLE_ASSERTIONS` now enables the extensive // hardening mode. -// `check_assertion.h` is only available starting from C++11 and requires Unix headers. -// UNSUPPORTED: c++03, !has-unix-headers +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization // The ability to set a custom abort message is required to compare the assertion message. // XFAIL: availability-verbose_abort-missing // Note that GCC doesn't support `-Wno-macro-redefined`. diff --git a/libcxx/test/libcxx/assertions/modes/override_with_debug_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_debug_mode.pass.cpp index 665babf59c259..f49ad490780c3 100644 --- a/libcxx/test/libcxx/assertions/modes/override_with_debug_mode.pass.cpp +++ b/libcxx/test/libcxx/assertions/modes/override_with_debug_mode.pass.cpp @@ -8,10 +8,8 @@ // This test ensures that we can override any hardening mode with the debug mode on a per-TU basis. -// `check_assertion.h` is only available starting from C++11. -// UNSUPPORTED: c++03 -// `check_assertion.h` requires Unix headers. -// REQUIRES: has-unix-headers +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization // The ability to set a custom abort message is required to compare the assertion message. // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG diff --git a/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp index e2b0ea7208118..f5323c671c9b1 100644 --- a/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp +++ b/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp @@ -8,10 +8,8 @@ // This test ensures that we can override any hardening mode with the extensive hardening mode on a per-TU basis. -// `check_assertion.h` is only available starting from C++11. -// UNSUPPORTED: c++03 -// `check_assertion.h` requires Unix headers. -// REQUIRES: has-unix-headers +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization // The ability to set a custom abort message is required to compare the assertion message. // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE diff --git a/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp index b38afed17e567..5ee22cc45f3bf 100644 --- a/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp +++ b/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp @@ -8,10 +8,8 @@ // This test ensures that we can override any hardening mode with the fast mode on a per-TU basis. -// `check_assertion.h` is only available starting from C++11. -// UNSUPPORTED: c++03 -// `check_assertion.h` requires Unix headers. -// REQUIRES: has-unix-headers +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization // The ability to set a custom abort message is required to compare the assertion message. // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST diff --git a/libcxx/test/libcxx/assertions/modes/override_with_unchecked_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_unchecked_mode.pass.cpp index 65707a9863d07..8ea8b731ec4d3 100644 --- a/libcxx/test/libcxx/assertions/modes/override_with_unchecked_mode.pass.cpp +++ b/libcxx/test/libcxx/assertions/modes/override_with_unchecked_mode.pass.cpp @@ -8,10 +8,8 @@ // This test ensures that we can override any hardening mode with the unchecked mode on a per-TU basis. -// `check_assertion.h` is only available starting from C++11. -// UNSUPPORTED: c++03 -// `check_assertion.h` requires Unix headers. -// REQUIRES: has-unix-headers +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE #include diff --git a/libcxx/test/libcxx/containers/sequences/deque/asan_caterpillar.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/asan_caterpillar.pass.cpp index b99b2737bce02..d3c6e0493ee28 100644 --- a/libcxx/test/libcxx/containers/sequences/deque/asan_caterpillar.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/deque/asan_caterpillar.pass.cpp @@ -11,8 +11,8 @@ // Regression test to error in deque::__annotate_from_to in deque, // with origin in deque::__add_back_capacity. -// REQUIRES: has-unix-headers -// UNSUPPORTED: c++03 +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// UNSUPPORTED: c++03, !has-unix-headers, no-localization #include #include diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp index f7279655cb129..dda642be85bc0 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp index ffe4f1866ebe6..bb8ab42172226 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp index 98fde95fb0e44..c02496bef4212 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp index d0b77661334d7..88d177a6e39f4 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp index 6c7149f4048ad..439204060e189 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp index ae5063c5264ea..d1c031bdd97a2 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp index 167c4ac4df95e..58fe79b34c008 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp index 4c2f9946165e7..1bcd858f3c02d 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp index 06b0810c257b3..b0ee4f8d062ef 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp index ab15bdf5d8b99..a63276f1e025d 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp index 9a6d8d636200c..26e6fea5904fe 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp index b56959809829b..b48a5a9fa2b7d 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp index 43ee937a8a185..1dc603cfaa554 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp index 65a112774ff76..d52889b1be147 100644 --- a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp index d2df251d5c8ad..5ac04334f0005 100644 --- a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: no-exceptions -// REQUIRES: has-unix-headers +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization // UNSUPPORTED: libcpp-has-no-incomplete-pstl diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h index 98dd95b11556e..65c93eded971d 100644 --- a/libcxx/test/support/check_assertion.h +++ b/libcxx/test/support/check_assertion.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -235,18 +236,26 @@ struct DeathTest { }; #ifdef _LIBCPP_VERSION -void std::__libcpp_verbose_abort(char const* format, ...) { - // Extract information from the error message. This has to stay synchronized with - // how we format assertions in the library. - va_list list; - va_start(list, format); - char const* file = va_arg(list, char const*); - int line = va_arg(list, int); - char const* expression = va_arg(list, char const*); (void)expression; - char const* message = va_arg(list, char const*); - va_end(list); - - if (GlobalMatcher().Matches(file, line, message)) { +void std::__libcpp_verbose_abort(char const* printf_format, ...) { + // Extract information from the error message. This has to stay synchronized with how we format assertions in the + // library. + va_list args; + va_start(args, printf_format); + char const* message = va_arg(args, char const*); + + std::regex message_format("(.*):(\\d+): assertion (.*) failed: (.*)\\n"); + + std::cmatch match_result; + bool has_match = std::regex_match(message, match_result, message_format); + assert(has_match); + assert(match_result.size() == 5); + + std::string file = match_result[1]; + int line = std::stoi(match_result[2]); + // Omitting `expression` in `match_result[3]` + std::string failure_reason = match_result[4]; + + if (GlobalMatcher().Matches(file.c_str(), line, failure_reason.c_str())) { std::exit(DeathTest::RK_MatchFound); } std::exit(DeathTest::RK_MatchFailure); diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index 54e18b5ea533d..326931b0081c0 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -168,6 +168,9 @@ def is_modulemap_header(header): if header == "__config_site": return False + if header == "__assertion_handler": + return False + # exclude libc++abi files if header in ["cxxabi.h", "__cxxabi_config.h"]: return False diff --git a/libcxx/vendor/llvm/default_assertion_handler.in b/libcxx/vendor/llvm/default_assertion_handler.in new file mode 100644 index 0000000000000..111d305a16f7c --- /dev/null +++ b/libcxx/vendor/llvm/default_assertion_handler.in @@ -0,0 +1,23 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ASSERTION_HANDLER +#define _LIBCPP___ASSERTION_HANDLER + +#include <__config> +#include <__verbose_abort> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// TODO(hardening): in production, trap rather than abort. +#define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message) + +#endif // _LIBCPP___ASSERTION_HANDLER