Skip to content

Commit

Permalink
[libc++] Rename __libcpp_assertion_handler to __libcpp_verbose_abort
Browse files Browse the repository at this point in the history
With the goal of reusing that handler to do other things besides
handling assertions (such as terminating when an exception is thrown
under -fno-exceptions), the name `__libcpp_assertion_handler` doesn't
really make sense anymore.

Furthermore, I didn't want to use the name `__libcpp_abort_handler`,
since that would give the impression that the handler is called
whenever `std::abort()` is called, which is not the case at all.

Differential Revision: https://reviews.llvm.org/D130562
  • Loading branch information
ldionne committed Jul 29, 2022
1 parent 4191d66 commit 507125a
Show file tree
Hide file tree
Showing 23 changed files with 230 additions and 210 deletions.
63 changes: 31 additions & 32 deletions libcxx/docs/UsingLibcxx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,28 +152,28 @@ where the static or shared library was compiled **with** assertions but the user
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 override that
assertion handler with their own, which can be useful to provide custom behavior, or when deploying
to older platforms where the default assertion handler isn't available.
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.

Replacing the default assertion handler is done by defining the following function:
Replacing the default verbose termination function is done by defining the following function:

.. code-block:: cpp
void __libcpp_assertion_handler(char const* format, ...)
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 <version> // must include any libc++ header before defining the handler (C compatibility headers excluded)
#include <version> // must include any libc++ header before defining the function (C compatibility headers excluded)
void std::__libcpp_assertion_handler(char const* format, ...) {
void std::__libcpp_verbose_abort(char const* format, ...) {
va_list list;
va_start(list, format);
std::vfprintf(stderr, format, list);
Expand All @@ -187,30 +187,29 @@ and ``operator delete``. For example:
int main() {
std::vector<int> v;
int& x = v[0]; // Your assertion handler will be called here if _LIBCPP_ENABLE_ASSERTIONS=1
int& x = v[0]; // Your termination function 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 and does return.

Furthermore, throwing an exception from the assertion handler is not recommended. Indeed, many
functions in the library are ``noexcept``, and any exception thrown from the assertion handler
will result in ``std::terminate`` being called.

Back-deploying with a custom assertion handler
----------------------------------------------
When deploying to an older platform that does not provide a default assertion handler, the
compiler will diagnose the usage of ``std::__libcpp_assertion_handler`` with an error. This
is done to avoid the load-time error that would otherwise happen if the code was being deployed
on the older system.

If you are providing a custom assertion handler, this error is effectively a false positive.
To let the library know that you are providing a custom assertion handler in back-deployment
scenarios, you must define the ``_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_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 the older platform, it will fail to load when the
dynamic linker fails to find a definition for ``std::__libcpp_assertion_handler``, so you
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.

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
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ set(files
__utility/transaction.h
__utility/unreachable.h
__variant/monostate.h
__verbose_abort
algorithm
any
array
Expand Down
11 changes: 2 additions & 9 deletions libcxx/include/__assert
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#ifndef _LIBCPP___ASSERT
#define _LIBCPP___ASSERT

#include <__availability>
#include <__config>
#include <__verbose_abort>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
Expand Down Expand Up @@ -45,7 +45,7 @@
# define _LIBCPP_ASSERT(expression, message) \
(__builtin_expect(static_cast<bool>(expression), 1) ? \
(void)0 : \
::std::__libcpp_assertion_handler("%s:%d: assertion %s failed: %s", __FILE__, __LINE__, #expression, message))
::std::__libcpp_verbose_abort("%s:%d: assertion %s failed: %s", __FILE__, __LINE__, #expression, message))
#elif !defined(_LIBCPP_ASSERTIONS_DISABLE_ASSUME) && __has_builtin(__builtin_assume)
# define _LIBCPP_ASSERT(expression, message) \
(_LIBCPP_DIAGNOSTIC_PUSH \
Expand All @@ -56,11 +56,4 @@
# define _LIBCPP_ASSERT(expression, message) ((void)0)
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ASSERTION_HANDLER _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
void __libcpp_assertion_handler(const char *__format, ...);

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ASSERT
41 changes: 20 additions & 21 deletions libcxx/include/__availability
Original file line number Diff line number Diff line change
Expand Up @@ -156,22 +156,21 @@
# define _LIBCPP_AVAILABILITY_FORMAT
// # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format

// This controls whether the std::__libcpp_assertion_handler default
// assertion handler is provided by the library.
// This controls whether the default verbose termination function is
// provided by the library.
//
// Note that when users provide their own custom assertion handler,
// it doesn't matter whether the dylib provides a default handler,
// and the availability markup can actually give a false positive
// diagnostic (it will think that no handler is provided, when in
// reality the user has provided their own).
// Note that when users provide their own custom function, it doesn't
// matter whether the dylib provides a default function, and the
// availability markup can actually give a false positive diagnostic
// (it will think that no function is provided, when in reality the
// user has provided their own).
//
// Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED
// Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED
// to the compiler to tell the library to ignore the fact that the
// default handler isn't available on their deployment target. Note that
// defining this macro but failing to define a custom assertion handler
// will lead to a load-time error on back-deployment targets, so it
// should be avoided.
# define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER
// 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

#elif defined(__APPLE__)

Expand Down Expand Up @@ -272,7 +271,7 @@
__attribute__((unavailable))
# define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format

# define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER \
# define _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT \
__attribute__((unavailable))
#else

Expand All @@ -297,14 +296,14 @@
# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
#endif

// Define the special assertion handler availability attribute, which can be silenced by
// users if they provide their own custom assertion handler. 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 handler.
#if defined(_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED)
# define _LIBCPP_AVAILABILITY_ASSERTION_HANDLER /* nothing */
// 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_ASSERTION_HANDLER _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER
# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT
#endif

#endif // _LIBCPP___AVAILABILITY
27 changes: 27 additions & 0 deletions libcxx/include/__verbose_abort
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// -*- 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___VERBOSE_ABORT
#define _LIBCPP___VERBOSE_ABORT

#include <__availability>
#include <__config>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
void __libcpp_verbose_abort(const char *__format, ...);

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___VERBOSE_ABORT
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,7 @@ module std [system] {
module __tree { header "__tree" export * }
module __tuple { private header "__tuple" export * }
module __undef_macros { header "__undef_macros" export * }
module __verbose_abort { header "__verbose_abort" export * }

module experimental {
requires cplusplus11
Expand Down
4 changes: 2 additions & 2 deletions libcxx/lib/abi/CHANGELOG.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Version 15.0
Symbol removed: _ZTSNSt3__18__c_nodeE
Symbol removed: _ZTVNSt3__18__c_nodeE

* b0fd9497af6d and 7de5aca84c54 - [libc++] Add a lightweight overridable assertion handler
* b0fd9497af6d, 7de5aca84c54 and XXXXXXXX - [libc++] Add a lightweight overridable assertion handler

This patch adds a lightweight assertion handler mechanism that can be
overriden at link-time in a fashion similar to `operator new`. A default
Expand All @@ -73,7 +73,7 @@ Version 15.0

All platforms
-------------
Symbol added: _ZNSt3__126__libcpp_assertion_handlerEPKcz
Symbol added: _ZNSt3__122__libcpp_verbose_abortEPKcz

------------
Version 14.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1534,7 +1534,7 @@
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__122__libcpp_verbose_abortEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1534,7 +1534,7 @@
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__122__libcpp_verbose_abortEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
Expand Down
2 changes: 1 addition & 1 deletion libcxx/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTOR
set(LIBCXX_SOURCES
algorithm.cpp
any.cpp
assert.cpp
atomic.cpp
barrier.cpp
bind.cpp
Expand Down Expand Up @@ -62,6 +61,7 @@ set(LIBCXX_SOURCES
valarray.cpp
variant.cpp
vector.cpp
verbose_abort.cpp
)

if (LIBCXX_ENABLE_DEBUG_MODE OR LIBCXX_ENABLE_BACKWARDS_COMPATIBILITY_DEBUG_MODE_SYMBOLS)
Expand Down
4 changes: 2 additions & 2 deletions libcxx/src/assert.cpp → libcxx/src/verbose_abort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//

#include <__assert>
#include <__config>
#include <__verbose_abort>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
Expand All @@ -29,7 +29,7 @@ extern "C" void android_set_abort_message(const char* msg);
_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_WEAK
void __libcpp_assertion_handler(char const* format, ...) {
void __libcpp_verbose_abort(char const* format, ...) {
// Write message to stderr. We do this before formatting into a
// buffer so that we still get some information out if that fails.
{
Expand Down
Loading

0 comments on commit 507125a

Please sign in to comment.