diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -82,6 +82,9 @@ // its vtable and typeinfo to libc++ rather than having all other libraries // using that class define their own copies. # define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION +// Override the default return value of `what()` function that comes from +// `std::exception` with a string that is specific to `bad_function_call`. +# define _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE // Enable optimized version of __do_get_(un)signed which avoids redundant copies. # define _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET // In C++20 and later, don't derive std::plus from std::binary_function, diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h --- a/libcxx/include/__functional/function.h +++ b/libcxx/include/__functional/function.h @@ -35,10 +35,21 @@ class _LIBCPP_EXCEPTION_ABI bad_function_call : public exception { -#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION public: +// Using a key function allows emitting a vtable and typeinfo for the class in +// a single translation unit. Originally `bad_function_call` didn't use a key +// function, and because changing this behavior constitutes an ABI break, +// it is controlled by a preprocessor definition. +#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION virtual ~bad_function_call() _NOEXCEPT; +#else + virtual ~bad_function_call() _NOEXCEPT {} +#endif +// Whether to use a `what` message specific to `bad_function_call`. This +// behavior is controlled by a preprocessor definition because changing it +// constitutes an ABI break (with `what` serving as a key function). +#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE virtual const char* what() const _NOEXCEPT; #endif }; diff --git a/libcxx/lib/abi/CHANGELOG.TXT b/libcxx/lib/abi/CHANGELOG.TXT --- a/libcxx/lib/abi/CHANGELOG.TXT +++ b/libcxx/lib/abi/CHANGELOG.TXT @@ -27,7 +27,6 @@ x86_64-apple-apple-darwin ------------------------- - Symbol added: __ZNKSt3__117bad_function_call4whatEv Symbol added: __ZNSt3__117bad_function_callD0Ev Symbol added: __ZNSt3__117bad_function_callD1Ev Symbol added: __ZNSt3__117bad_function_callD2Ev @@ -37,7 +36,6 @@ x86_64-unknown-linux-gnu ------------------------ - Symbol added: _ZNKSt3__117bad_function_call4whatEv Symbol added: _ZNSt3__117bad_function_callD0Ev Symbol added: _ZNSt3__117bad_function_callD1Ev Symbol added: _ZNSt3__117bad_function_callD2Ev diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist --- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist @@ -497,7 +497,6 @@ {'is_defined': True, 'name': '__ZNKSt3__115basic_streambufIwNS_11char_traitsIwEEE6getlocEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE3strEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__115error_condition7messageEv', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNKSt3__117bad_function_call4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__117moneypunct_bynameIcLb0EE11do_groupingEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__117moneypunct_bynameIcLb0EE13do_neg_formatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__117moneypunct_bynameIcLb0EE13do_pos_formatEv', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist @@ -1,5 +1,6 @@ {'is_defined': False, 'name': '_ZNKSt11logic_error4whatEv', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNKSt13runtime_error4whatEv', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZNKSt9exception4whatEv', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt11logic_errorD2Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt12length_errorD1Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt12out_of_rangeD1Ev', 'type': 'FUNC'} @@ -35,12 +36,15 @@ {'is_defined': False, 'name': '_ZTVSt13runtime_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTVSt14overflow_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTVSt16invalid_argument', 'size': 0, 'type': 'OBJECT'} +{'is_defined': False, 'name': '_ZTVSt9exception', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZdaPv', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZdaPvSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZdlPv', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZdlPvSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_Znam', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZnamSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_Znwm', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_allocate_exception', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_begin_catch', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_current_primary_exception', 'type': 'FUNC'} @@ -230,7 +234,6 @@ {'is_defined': True, 'name': '_ZNKSt3__115basic_streambufIwNS_11char_traitsIwEEE6getlocEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE3strEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__115error_condition7messageEv', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNKSt3__117bad_function_call4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__117moneypunct_bynameIcLb0EE11do_groupingEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__117moneypunct_bynameIcLb0EE13do_neg_formatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__117moneypunct_bynameIcLb0EE13do_pos_formatEv', 'type': 'FUNC'} @@ -1980,6 +1983,8 @@ {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 96, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTVNSt3__120__time_get_c_storageIcEE', 'size': 72, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTVNSt3__120__time_get_c_storageIwEE', 'size': 72, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__14__fs10filesystem16filesystem_errorE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIcEE', 'size': 104, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIwEE', 'size': 136, 'type': 'OBJECT'} diff --git a/libcxx/src/functional.cpp b/libcxx/src/functional.cpp --- a/libcxx/src/functional.cpp +++ b/libcxx/src/functional.cpp @@ -14,7 +14,9 @@ bad_function_call::~bad_function_call() noexcept { } +#endif +#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE const char* bad_function_call::what() const noexcept { diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp @@ -15,6 +15,19 @@ // This test runs in C++03, but we have deprecated using std::function in C++03. // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS +// Address Sanitizer doesn't instrument weak symbols on Linux. Because the key +// function is conditionally defined for bad_function_call, its typeinfo and +// vtable will be defined as strong symbols in the library and weak symbols in +// other translation units. Only the strong symbol will be instrumented, +// increasing its size and leading to a serious ODR violation resulting in +// a crash. +// Some relevant bugs: +// https://github.com/google/sanitizers/issues/1017 +// https://github.com/google/sanitizers/issues/619 +// https://github.com/google/sanitizers/issues/398 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68016 +// UNSUPPORTED: asan + #include #include