Skip to content

Commit 17c05a4

Browse files
committed
[libc++] Introduce a compile-time mechanism to override __libcpp_verbose_abort
This changes the mechanism for verbose termination (again!) to make it support compile-time customization in addition to link-time customization, which is important for users who need fine-grained control over what code gets generated around sites that call the verbose termination handler. This concern had been raised to me both privately by prospecting users and in https://llvm.org/D140944, so I think it is clearly worth fixing. We still support _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED for a limited time since the same functionality can be achieved by overriding the _LIBCPP_VERBOSE_ABORT macro. Differential Revision: https://reviews.llvm.org/D141326
1 parent 19f100e commit 17c05a4

9 files changed

+87
-49
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ Upcoming Deprecations and Removals
140140
and such a base template is bound to be incorrect for some types, which could currently cause unexpected
141141
behavior while going undetected.
142142

143+
- The ``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro will not be honored anymore in LLVM 18.
144+
Please see the updated documentation about the safe libc++ mode and in particular the ``_LIBCPP_VERBOSE_ABORT``
145+
macro for details.
146+
143147
API Changes
144148
-----------
145149
- The comparison operators on ``thread::id`` are now defined as free-standing

libcxx/docs/UsingLibcxx.rst

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,19 @@ library provides a default function that prints an error message and calls ``std
172172
that this function is provided by the static or shared library, so it is only available when deploying
173173
to a platform where the compiled library is sufficiently recent. On older platforms, the program will
174174
terminate in an unspecified unsuccessful manner, but the quality of diagnostics won't be great.
175-
However, users can also override that function with their own, which can be useful to either provide
176-
custom behavior or when deploying to an older platform where the default function isn't available.
177-
178-
Replacing the default verbose termination function is done by defining the
179-
``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro in all translation units of your program
180-
and defining the following function in exactly one translation unit:
175+
However, users can also override that mechanism at two different levels. First, the mechanism can be
176+
overriden at compile-time by defining the ``_LIBCPP_VERBOSE_ABORT(format, args...)`` variadic macro.
177+
When that macro is defined, it will be called with a format string as the first argument, followed by
178+
a series of arguments to format using printf-style formatting. Compile-time customization may be
179+
interesting to get precise control over code generation, however it is also inconvenient to use in
180+
some cases. Indeed, compile-time customization of the verbose termination function requires that all
181+
translation units be compiled with a consistent definition for ``_LIBCPP_VERBOSE_ABORT`` to avoid ODR
182+
violations, which can add complexity in the build system of users.
183+
184+
Otherwise, if compile-time customization is not necessary, link-time customization of the handler is also
185+
possible, similarly to how replacing ``operator new`` works. This mechanism trades off fine-grained control
186+
over the call site where the termination is initiated in exchange for more ergonomics. Link-time customization
187+
is done by simply defining the following function in exactly one translation unit of your program:
181188

182189
.. code-block:: cpp
183190

libcxx/include/__assert

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
# define _LIBCPP_ASSERT(expression, message) \
4242
(__builtin_expect(static_cast<bool>(expression), 1) ? \
4343
(void)0 : \
44-
::std::__libcpp_verbose_abort("%s:%d: assertion %s failed: %s", __FILE__, __LINE__, #expression, message))
44+
_LIBCPP_VERBOSE_ABORT("%s:%d: assertion %s failed: %s", __FILE__, __LINE__, #expression, message))
4545
#elif !defined(_LIBCPP_ASSERTIONS_DISABLE_ASSUME) && __has_builtin(__builtin_assume)
4646
# define _LIBCPP_ASSERT(expression, message) \
4747
(_LIBCPP_DIAGNOSTIC_PUSH \

libcxx/include/__availability

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,9 @@
156156
# define _LIBCPP_AVAILABILITY_FORMAT
157157
// # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format
158158

159-
// This controls whether the default verbose termination function is
160-
// provided by the library.
161-
//
162-
// Note that when users provide their own custom function, it doesn't
163-
// matter whether the dylib provides a default function, and the
164-
// availability markup can actually give a false positive diagnostic
165-
// (it will think that no function is provided, when in reality the
166-
// user has provided their own).
167-
//
168-
// Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED
169-
// to the compiler to tell the library not to define its own verbose abort.
170-
// Note that defining this macro but failing to define a custom function
171-
// will lead to a load-time error on back-deployment targets, so it should
172-
// be avoided.
159+
// This controls whether the library claims to provide a default verbose
160+
// termination function, and consequently whether the headers will try
161+
// to use it when the mechanism isn't overriden at compile-time.
173162
// # define _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY
174163

175164
#elif defined(__APPLE__)

libcxx/include/__verbose_abort

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,41 @@
1717
# pragma GCC system_header
1818
#endif
1919

20-
// Provide a default implementation of __libcpp_verbose_abort if we know that neither the built
21-
// library nor the user is providing one. Otherwise, just declare it and use the one from the
22-
// built library or the one provided by the user.
23-
//
24-
// We can't provide a great implementation because it needs to be pretty much
25-
// dependency-free (this is included everywhere else in the library).
26-
#if defined(_LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY) && !defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)
27-
28-
_LIBCPP_BEGIN_NAMESPACE_STD
29-
30-
_LIBCPP_NORETURN _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) _LIBCPP_HIDE_FROM_ABI inline
31-
void __libcpp_verbose_abort(const char *, ...) {
32-
__builtin_abort();
33-
}
34-
35-
_LIBCPP_END_NAMESPACE_STD
36-
37-
#else
38-
3920
_LIBCPP_BEGIN_NAMESPACE_STD
4021

22+
// This function should never be called directly from the code -- it should only be called through
23+
// the _LIBCPP_VERBOSE_ABORT macro.
4124
_LIBCPP_NORETURN _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
4225
void __libcpp_verbose_abort(const char *__format, ...);
4326

44-
_LIBCPP_END_NAMESPACE_STD
27+
// _LIBCPP_VERBOSE_ABORT(format, args...)
28+
//
29+
// This macro is used to abort the program abnormally while providing additional diagnostic information.
30+
//
31+
// The first argument is a printf-style format string, and the remaining arguments are values to format
32+
// into the format-string. This macro can be customized by users to provide fine-grained control over
33+
// how verbose termination is triggered.
34+
//
35+
// If the user does not supply their own version of the _LIBCPP_VERBOSE_ABORT macro, we pick the default
36+
// behavior based on whether we know the built library we're running against provides support for the
37+
// verbose termination handler or not. If it does, we call it. If it doesn't, we call __builtin_abort to
38+
// make sure that the program terminates but without taking any complex dependencies in this header.
39+
#if !defined(_LIBCPP_VERBOSE_ABORT)
40+
41+
// Support _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED until LLVM 18, but tell people
42+
// to move to customizing _LIBCPP_VERBOSE_ABORT instead.
43+
# if defined(_LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY) && defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)
44+
# undef _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY
45+
# warning _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED is deprecated, please customize _LIBCPP_VERBOSE_ABORT instead
46+
# endif
47+
48+
# if defined(_LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY)
49+
# define _LIBCPP_VERBOSE_ABORT(...) __builtin_abort()
50+
# else
51+
# define _LIBCPP_VERBOSE_ABORT(...) ::std::__libcpp_verbose_abort(__VA_ARGS__)
52+
# endif
53+
#endif // !defined(_LIBCPP_VERBOSE_ABORT)
4554

46-
#endif
55+
_LIBCPP_END_NAMESPACE_STD
4756

4857
#endif // _LIBCPP___VERBOSE_ABORT
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// This compile-time customization requires cross-file macros, which doesn't work with modules.
10+
// UNSUPPORTED: modules-build
11+
12+
// Make sure that we can customize the verbose termination function at compile-time by
13+
// defining _LIBCPP_VERBOSE_ABORT ourselves. Note that this does not have any
14+
// deployment target requirements.
15+
16+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 -D_LIBCPP_VERBOSE_ABORT(...)=my_abort(__VA_ARGS__)
17+
18+
#include <cstdlib>
19+
20+
void my_abort(char const*, ...) {
21+
std::exit(EXIT_SUCCESS);
22+
}
23+
24+
int main(int, char**) {
25+
_LIBCPP_ASSERT(false, "message");
26+
return EXIT_FAILURE;
27+
}

libcxx/test/libcxx/assertions/customize_verbose_abort.pass.cpp renamed to libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// Test that we can set a custom verbose termination function.
9+
// Test that we can set a custom verbose termination function at link-time.
1010

1111
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
1212

libcxx/test/libcxx/assertions/customize_verbose_abort.backdeployment.pass.cpp renamed to libcxx/test/libcxx/assertions/deprecated-link-time-custom-handler.pass.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// Make sure that we can enable assertions when we back-deploy to older platforms
10-
// if we define _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED.
11-
//
12-
// Note that this test isn't really different from customize_verbose_abort.pass.cpp when
13-
// run outside of back-deployment scenarios, but we always want to run this test.
9+
// Make sure that we still support _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED for folks
10+
// who customize the verbose termination function at link-time in back-deployment environments.
1411

1512
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 -D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED
1613

14+
// We emit a #warning about the deprecation of this setting, so make sure we don't turn that into an error.
15+
// ADDITIONAL_COMPILE_FLAGS: -Wno-error
16+
1717
#include <cstdlib>
1818

1919
void std::__libcpp_verbose_abort(char const*, ...) {

libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// Test that all public C++ headers define the verbose termination function.
9+
// Test that all public C++ headers define the verbose termination function, which
10+
// is required for users to be able to include any public header and then override
11+
// the function using a strong definition.
1012

1113
// The system-provided <uchar.h> seems to be broken on AIX, which trips up this test.
1214
// XFAIL: LIBCXX-AIX-FIXME

0 commit comments

Comments
 (0)