diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -82,7 +82,10 @@ include(HandleCompilerRT) # Basic options --------------------------------------------------------------- -option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." OFF) +option(LIBCXX_ENABLE_ASSERTIONS + "Enable assertions inside the compiled library, and at the same time make it the + default when compiling user code. Note that assertions can be enabled or disabled + by users in their own code regardless of this option." OFF) option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON) option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON) @@ -675,9 +678,6 @@ endif() # Assertion flags ============================================================= -define_if(LIBCXX_ENABLE_ASSERTIONS -UNDEBUG) -define_if_not(LIBCXX_ENABLE_ASSERTIONS -DNDEBUG) -define_if(LIBCXX_ENABLE_ASSERTIONS -D_LIBCPP_DEBUG=0) define_if(LIBCXX_DEBUG_BUILD -D_DEBUG) if (LIBCXX_ENABLE_ASSERTIONS AND NOT LIBCXX_DEBUG_BUILD) # MSVC doesn't like _DEBUG on release builds. See PR 4379. @@ -879,6 +879,11 @@ config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE) config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS) config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) +if (LIBCXX_ENABLE_ASSERTIONS) + config_define(1 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT) +else() + config_define(0 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT) +endif() # Incomplete features get their own specific disabling flags. This makes it # easier to grep for target specific flags once the feature is complete. config_define_if_not(LIBCXX_ENABLE_INCOMPLETE_FEATURES _LIBCPP_HAS_NO_INCOMPLETE_FORMAT) diff --git a/libcxx/benchmarks/algorithms.bench.cpp b/libcxx/benchmarks/algorithms.bench.cpp --- a/libcxx/benchmarks/algorithms.bench.cpp +++ b/libcxx/benchmarks/algorithms.bench.cpp @@ -151,7 +151,6 @@ template void sortValues(T& V, Order O) { - assert(std::is_sorted(V.begin(), V.end())); switch (O) { case Order::Random: { std::random_device R; diff --git a/libcxx/cmake/caches/Generic-assertions.cmake b/libcxx/cmake/caches/Generic-assertions.cmake --- a/libcxx/cmake/caches/Generic-assertions.cmake +++ b/libcxx/cmake/caches/Generic-assertions.cmake @@ -1 +1,3 @@ set(LIBCXX_ENABLE_ASSERTIONS ON CACHE BOOL "") +set(LIBCXX_TEST_PARAMS "enable_assertions=True" CACHE STRING "") +set(LIBCXXABI_TEST_PARAMS "enable_assertions=True" CACHE STRING "") diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst --- a/libcxx/docs/BuildingLibcxx.rst +++ b/libcxx/docs/BuildingLibcxx.rst @@ -216,7 +216,10 @@ **Default**: ``OFF`` - Build libc++ with assertions enabled. + Build libc++ with assertions enabled in the compiled library, and enable assertions + by default when building user code as well. Assertions can be turned off by users + by defining ``_LIBCPP_ENABLE_ASSERTIONS=0``. For details, see + :ref:`the documentation `. .. option:: LIBCXX_ENABLE_SHARED:BOOL diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -69,6 +69,12 @@ - The C++14 function ``std::quoted(const char*)`` is no longer supported in C++03 or C++11 modes. +- Libc++ now supports a variety of assertions that can be turned on to help catch + undefined behavior in user code. This new support is now separate from the old + (and incomplete) Debug Mode. Vendors can select whether the library they ship + should include assertions or not by default. For details, see + :ref:`the documentation ` about this new feature. + ABI Changes ----------- diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -121,6 +121,72 @@ +.. _assertions-mode: + +Enabling the "safe libc++" mode +=============================== + +Libc++ contains a number of assertions whose goal is to catch undefined behavior in the +library, usually caused by precondition violations. Those assertions do not aim to be +exhaustive -- instead they aim to provide a good balance between safety and performance. +In particular, these assertions do not change the complexity of algorithms. However, they +might, in some cases, interfere with compiler optimizations. + +By default, these assertions are turned off. Vendors can decide to turn them on while building +the compiled library by defining ``LIBCXX_ENABLE_ASSERTIONS=ON`` at CMake configuration time. +When ``LIBCXX_ENABLE_ASSERTIONS`` is used, the compiled library will be built with assertions +enabled, **and** user code will be built with assertions enabled by default. If ``LIBCXX_ENABLE_ASSERTIONS=OFF`` +at CMake configure time, the compiled library will not contain assertions and the default when +building user code will be to have assertions disabled. + +Independently of any vendor-selected default, users can always control whether assertions +are enabled in their code by defining ``_LIBCPP_ENABLE_ASSERTIONS=0|1`` before including any +libc++ header. Note that if the compiled library was built by the vendor without assertions, +functions compiled inside the static or shared library won't have assertions enabled even if +the user defines ``_LIBCPP_ENABLE_ASSERTIONS=1`` (the same is true for the inverse case where +the static or shared library was compiled **with** assertions but the user tries to disable +them). However, most of the code in libc++ is in the headers, so the user-selected value for +``_LIBCPP_ENABLE_ASSERTIONS`` (if any) will usually be respected. + +When an assertion fails, an assertion handler function is called. The library provides a default +assertion handler that prints an error message and calls ``std::abort()``. Note that this assertion +handler 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 define their +own assertion handler to replace the default one, which can be useful to provide custom behavior, +or when deploying to older platforms where the default assertion handler isn't available. + +Replacing the default assertion handler is done by defining the ``_LIBCPP_ASSERTION_HANDLER`` macro, +which is called with an instance of ``std::__libcpp_assertion_info``. Generally speaking, +``_LIBCPP_ASSERTION_HANDLER`` should expand to a fully qualified function name. For example: + +.. code-block:: cpp + + // In HelloWorldHandler.h + #define _LIBCPP_ASSERTION_HANDLER ::HelloWorldAssertionHandler + #include <__assert> + + // This could also be defined in another translation unit, but we're defining it inline + // for simplicity in this example. + inline [[noreturn]] void HelloWorldAssertionHandler(std::__libcpp_assertion_info info) { + std::printf("Assertion %s failed at %s:%d, more info: %s", + info.__predicate(), info.file(), info.__line(), info.__message()); + std::abort(); + } + + // In HelloWorld.cpp + // Note: You must add `-include path/to/HelloWorldHandler.h` to your compiler flags. + #include + + int main() { + std::vector v; + int& x = v[0]; // Your assertion handler will be called here if _LIBCPP_ENABLE_ASSERTIONS=1 + } + +Also note that the assertion handler should usually not return. Since the assertions in libc++ +catch undefined behavior, your code will proceed with undefined behavior if your assertion +handler is called but does return. + + Libc++ Configuration Macros =========================== diff --git a/libcxx/include/__assert b/libcxx/include/__assert --- a/libcxx/include/__assert +++ b/libcxx/include/__assert @@ -10,6 +10,7 @@ #ifndef _LIBCPP___ASSERT #define _LIBCPP___ASSERT +#include <__availability> #include <__config> #include // for std::string @@ -17,14 +18,39 @@ # pragma GCC system_header #endif +// This is for backwards compatibility with code that might have been enabling +// assertions through the Debug mode previously. #if _LIBCPP_DEBUG_LEVEL >= 1 -# define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : ::std::__libcpp_debug_function(::std::__libcpp_debug_info(__FILE__, __LINE__, #x, m))) +# ifndef _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_ENABLE_ASSERTIONS 1 +# endif +# ifndef _LIBCPP_ASSERTION_HANDLER +# define _LIBCPP_ASSERTION_HANDLER ::std::__libcpp_debug_function +# endif +#endif + +#ifndef _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_ENABLE_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS_DEFAULT +#endif + +#if _LIBCPP_ENABLE_ASSERTIONS != 0 && _LIBCPP_ENABLE_ASSERTIONS != 1 +# error "_LIBCPP_ENABLE_ASSERTIONS must be set to 0 or 1" +#endif + +#ifndef _LIBCPP_ASSERTION_HANDLER +# define _LIBCPP_ASSERTION_HANDLER ::std::__libcpp_default_assertion_handler +#endif + +#if _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : _LIBCPP_ASSERTION_HANDLER(::std::__libcpp_assertion_info(__FILE__, __LINE__, #x, m))) #else -# define _LIBCPP_ASSERT(x, m) ((void)0) +# define _LIBCPP_ASSERT(x, m) ((void)0) #endif _LIBCPP_BEGIN_NAMESPACE_STD +////////////////////////////////////////////////////////////////// +// For backwards compatibility with clients of the Debug mode struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info { _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_debug_info() @@ -56,6 +82,41 @@ /// function. _LIBCPP_FUNC_VIS bool __libcpp_set_debug_function(__libcpp_debug_function_type __func); +////////////////////////////////////////////////////////////////// + +struct __libcpp_assertion_info { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + explicit __libcpp_assertion_info(char const* __file, int __line, char const* __predicate, char const* __message) + : __file_(__file), __line_(__line), __predicate_(__predicate), __message_(__message) + { } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + char const* __file() const { return __file_; } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + int __line() const { return __line_; } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + char const* __predicate() const { return __predicate_; } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + char const* __message() const { return __message_; } + + // For backwards compatibility + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + operator __libcpp_debug_info() const { + return __libcpp_debug_info(__file_, __line_, __predicate_, __message_); + } + +private: + char const* __file_; + int __line_; + char const* __predicate_; + char const* __message_; +}; + +_LIBCPP_NORETURN _LIBCPP_AVAILABILITY_ASSERTION_HANDLER _LIBCPP_EXPORTED_FROM_ABI +void __libcpp_default_assertion_handler(__libcpp_assertion_info); _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__availability b/libcxx/include/__availability --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -81,6 +81,11 @@ #if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) + // This controls whether the default assertion handler is provided by the library. + // When the default assertion handler is not provided, users either can't enable + // assertions in the library, or must provide their own assertion handler. +# define _LIBCPP_AVAILABILITY_ASSERTION_HANDLER + // This controls the availability of std::shared_mutex and std::shared_timed_mutex, // which were added to the dylib later. # define _LIBCPP_AVAILABILITY_SHARED_MUTEX @@ -151,6 +156,9 @@ #elif defined(__APPLE__) +# define _LIBCPP_AVAILABILITY_ASSERTION_HANDLER \ + __attribute__((unavailable)) + # define _LIBCPP_AVAILABILITY_SHARED_MUTEX \ __attribute__((availability(macosx,strict,introduced=10.12))) \ __attribute__((availability(ios,strict,introduced=10.0))) \ diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in --- a/libcxx/include/__config_site.in +++ b/libcxx/include/__config_site.in @@ -32,6 +32,7 @@ #cmakedefine _LIBCPP_HAS_NO_WIDE_CHARACTERS #cmakedefine _LIBCPP_HAS_NO_INCOMPLETE_FORMAT #cmakedefine _LIBCPP_HAS_NO_INCOMPLETE_RANGES +#cmakedefine01 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT // __USE_MINGW_ANSI_STDIO gets redefined on MinGW #ifdef __clang__ diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist --- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist +++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist @@ -1581,6 +1581,7 @@ {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist --- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist +++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist @@ -1552,6 +1552,7 @@ {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist --- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist @@ -1581,6 +1581,7 @@ {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist --- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist @@ -1552,6 +1552,7 @@ {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist @@ -1272,6 +1272,7 @@ {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist @@ -1269,6 +1269,7 @@ {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist @@ -1246,6 +1246,7 @@ {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist @@ -1244,6 +1244,7 @@ {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__134__libcpp_default_assertion_handlerENS_23__libcpp_assertion_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE', 'type': 'FUNC'} diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -4,6 +4,7 @@ set(LIBCXX_SOURCES algorithm.cpp any.cpp + assert.cpp atomic.cpp barrier.cpp bind.cpp @@ -65,7 +66,6 @@ if (LIBCXX_ENABLE_DEBUG_MODE_SUPPORT) list(APPEND LIBCXX_SOURCES - assert.cpp debug.cpp ) endif() diff --git a/libcxx/src/assert.cpp b/libcxx/src/assert.cpp --- a/libcxx/src/assert.cpp +++ b/libcxx/src/assert.cpp @@ -10,29 +10,13 @@ #include <__config> #include #include -#include _LIBCPP_BEGIN_NAMESPACE_STD -std::string __libcpp_debug_info::what() const { - string msg = __file_; - msg += ":" + std::to_string(__line_) + ": _LIBCPP_ASSERT '"; - msg += __pred_; - msg += "' failed. "; - msg += __msg_; - return msg; -} - -_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { - std::fprintf(stderr, "%s\n", info.what().c_str()); - std::abort(); -} - -constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function; - -bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { - __libcpp_debug_function = __func; - return true; +void __libcpp_default_assertion_handler(__libcpp_assertion_info __info) { + std::fprintf(stderr, "%s:%d: libc++ assertion '%s' failed. %s\n", + __info.__file(), __info.__line(), __info.__predicate(), __info.__message()); + std::abort(); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/debug.cpp b/libcxx/src/debug.cpp --- a/libcxx/src/debug.cpp +++ b/libcxx/src/debug.cpp @@ -24,6 +24,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD +std::string __libcpp_debug_info::what() const { + string msg = __file_; + msg += ":" + std::to_string(__line_) + ": _LIBCPP_ASSERT '"; + msg += __pred_; + msg += "' failed. "; + msg += __msg_; + return msg; +} + +_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { + std::fprintf(stderr, "%s\n", info.what().c_str()); + std::abort(); +} + +constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function; + +bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { + __libcpp_debug_function = __func; + return true; +} + _LIBCPP_FUNC_VIS __libcpp_db* __get_db() diff --git a/libcxx/test/libcxx/assertion_handler.legacy_debug_mode.pass.cpp b/libcxx/test/libcxx/assertion_handler.legacy_debug_mode.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertion_handler.legacy_debug_mode.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Test that we still honor any legacy debug handler set in user code. + +#define _LIBCPP_DEBUG 0 +#include +#include // any random header that definitely includes assertions + +bool handler_called = false; +inline void HelloWorldDebugHandler(std::__libcpp_debug_info const&) { + handler_called = true; +} + +int main(int, char**) { + std::__libcpp_set_debug_function(&HelloWorldDebugHandler); + _LIBCPP_ASSERT(false, "message"); + assert(handler_called); + return 0; +} diff --git a/libcxx/test/libcxx/assertion_handler.pass.cpp b/libcxx/test/libcxx/assertion_handler.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertion_handler.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Test that we can set a custom assertion handler. + +#define _LIBCPP_ENABLE_ASSERTIONS 1 +#define _LIBCPP_ASSERTION_HANDLER ::HelloWorldAssertionHandler +#include <__assert> + +bool handler_called = false; +inline void HelloWorldAssertionHandler(std::__libcpp_assertion_info) { + handler_called = true; +} + +#include + +int main(int, char**) { + _LIBCPP_ASSERT(false, "message"); + assert(handler_called); + return 0; +} diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -177,6 +177,11 @@ AddFeature('libcxx-no-debug-mode') ]), + Parameter(name='enable_assertions', choices=[True, False], type=bool, default=False, + help="Whether to enable assertions when compiling the test suite. This is only meaningful when " + "running the tests against libc++.", + actions=lambda assertions: [AddCompileFlag('-D_LIBCPP_ENABLE_ASSERTIONS=1')] if assertions else []), + Parameter(name='additional_features', type=list, default=[], help="A comma-delimited list of additional features that will be enabled when running the tests. " "This should be used sparingly since specifying ad-hoc features manually is error-prone and "