diff --git a/libcxx/docs/TestingLibcxx.rst b/libcxx/docs/TestingLibcxx.rst --- a/libcxx/docs/TestingLibcxx.rst +++ b/libcxx/docs/TestingLibcxx.rst @@ -98,8 +98,7 @@ The libc++ test suite uses a few optional tools to improve the code quality. These tools are: -- clang-query -- clang-tidy +- clang-tidy (you might need additional dev packages to compile libc++-specific clang-tidy checks) Writing Tests ------------- diff --git a/libcxx/include/__memory_resource/unsynchronized_pool_resource.h b/libcxx/include/__memory_resource/unsynchronized_pool_resource.h --- a/libcxx/include/__memory_resource/unsynchronized_pool_resource.h +++ b/libcxx/include/__memory_resource/unsynchronized_pool_resource.h @@ -85,7 +85,7 @@ void do_deallocate(void* __p, size_t __bytes, size_t __align) override; - _LIBCPP_HIDE_FROM_ABI bool do_is_equal(const memory_resource& __other) const _NOEXCEPT override { + _LIBCPP_HIDE_FROM_ABI_VIRTUAL bool do_is_equal(const memory_resource& __other) const _NOEXCEPT override { return &__other == this; } diff --git a/libcxx/test/libcxx/clang_query.sh.cpp b/libcxx/test/libcxx/clang_query.sh.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/clang_query.sh.cpp +++ /dev/null @@ -1,277 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// Run clang-query on the headers - see clang_query/README.md for more information - -// REQUIRES: has-clang-query - -// The attributes hide_from_abi_of_visible.query relies on aren't applied on windows. -// XFAIL: windows - -// RUN: %{clang-query} -f %S/clang_query/hide_from_abi_or_visible.query %s --use-color -- -Wno-unknown-warning-option %{compile_flags} -fno-modules > %t.output -// RUN: cat %t.output -// RUN: cat %t.output | wc -l | grep -Fxq 1 - -// RUN: %{clang-query} -f %S/clang_query/abi_tag_on_virtual.query %s --use-color -- -Wno-unknown-warning-option %{compile_flags} -fno-modules > %t.output -// RUN: cat %t.output -// RUN: cat %t.output | wc -l | grep -Fxq 1 - -// Prevent from generating deprecated warnings for this test. -#if defined(__DEPRECATED) -# undef __DEPRECATED -#endif - -/* -BEGIN-SCRIPT - -for header in public_headers: - print("{}#{}include <{}>{}".format( - '#if ' + header_restrictions[header] + '\n' if header in header_restrictions else '', - 3 * ' ' if header in header_restrictions else '', - header, - '\n#endif' if header in header_restrictions else '' - )) - -END-SCRIPT -*/ - -// DO NOT MANUALLY EDIT ANYTHING BETWEEN THE MARKERS BELOW -// GENERATED-MARKER -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -# include -#endif -#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -# include -#endif -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) -# include -#endif -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#if __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include -#endif -#include -#include -#if !defined(_LIBCPP_HAS_NO_THREADS) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -# include -#endif -#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#if __cplusplus >= 201103L -# include -#endif -#include -#include -// GENERATED-MARKER diff --git a/libcxx/test/libcxx/clang_query/README.md b/libcxx/test/libcxx/clang_query/README.md deleted file mode 100644 --- a/libcxx/test/libcxx/clang_query/README.md +++ /dev/null @@ -1,4 +0,0 @@ - -This directory contains [AST matchers](https://clang.llvm.org/docs/LibASTMatchers.html) for clang-query. -These allow us to enforce some rules in the libc++ source code which are hard to enforce through other means, -like clang-tidy or regex matchers. diff --git a/libcxx/test/libcxx/clang_query/abi_tag_on_virtual.query b/libcxx/test/libcxx/clang_query/abi_tag_on_virtual.query deleted file mode 100644 --- a/libcxx/test/libcxx/clang_query/abi_tag_on_virtual.query +++ /dev/null @@ -1,29 +0,0 @@ -#===------------------------------------------------------------------------===# -# -# 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 -# -#===------------------------------------------------------------------------===# - -# This clang-query test ensures that we don't place an abi_tag attribute on -# virtual functions. This can happen by mistakenly applying a macro like -# _LIBCPP_HIDE_FROM_ABI on a virtual function. -# -# The problem is that arm64e pointer authentication extensions use the mangled -# name of the function to sign the function pointer in the vtable, which means -# that the ABI tag effectively influences how the pointers are signed. -# -# This can lead to PAC failures when passing an object that holds one of these -# pointers in its vtable across an ABI boundary if the two sides have been compiled -# with different versions of libc++: one side will sign the pointer using one function -# mangling (with one ABI tag), and the other side will authenticate the pointer expecting -# it to have a different mangled name due to the ABI tag being different, which will crash. -# -# This test ensures that we don't re-introduce this issue in the code base. - -match -cxxMethodDecl(isVirtual(), - hasAttr("attr::AbiTag"), - unless(isExpansionInSystemHeader()) - ) diff --git a/libcxx/test/libcxx/clang_query/hide_from_abi_or_visible.query b/libcxx/test/libcxx/clang_query/hide_from_abi_or_visible.query deleted file mode 100644 --- a/libcxx/test/libcxx/clang_query/hide_from_abi_or_visible.query +++ /dev/null @@ -1,37 +0,0 @@ -#===------------------------------------------------------------------------===# -# -# 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 -# -#===------------------------------------------------------------------------===# - -# Check that all functions in the libc++ headers are either marked with hidden -# visibility or default visibility - -# TODO: enable the check for all functions once we don't force-inline everything with GCC -match -functionDecl( - unless( - anyOf( - hasName("__introsort"), - hasName("__inplace_merge"), - hasName("__libcpp_snprintf_l"), - hasName("__libcpp_asprintf_l"), - hasName("__libcpp_sscanf_l"), - hasName("__tree_sub_invariant"), - hasName("__stable_sort_move"), - hasName("__stable_sort"), - hasName("__stable_partition"), - hasName("__lock_first"), - hasName("__stable_partition_impl"), - hasAttr("attr::Visibility"), - hasAttr("attr::AbiTag"), - cxxMethodDecl(), # We have explicitly instantiated classes and some of their methods don't have these attributes - isDeleted(), - isConsteval(), - isExpansionInSystemHeader() - ) - ), - isDefinition() -) diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt --- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt +++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt @@ -6,11 +6,13 @@ find_package(Clang 16) set(SOURCES + abi_tag_on_virtual.cpp + hide_from_abi.cpp robust_against_adl.cpp - libcpp_module.cpp qualify_declval.cpp - ) + libcpp_module.cpp + ) if(NOT Clang_FOUND) message(STATUS "Could not find a suitable version of the Clang development package; diff --git a/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.hpp b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.hpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.hpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" + +namespace libcpp { +class abi_tag_on_virtual : public clang::tidy::ClangTidyCheck { +public: + abi_tag_on_virtual(llvm::StringRef, clang::tidy::ClangTidyContext*); + void registerMatchers(clang::ast_matchers::MatchFinder*) override; + void check(const clang::ast_matchers::MatchFinder::MatchResult&) override; +}; +} // namespace libcpp diff --git a/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.cpp b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" +#include "clang-tidy/ClangTidyModuleRegistry.h" + +#include "abi_tag_on_virtual.hpp" + +// This clang-tidy check ensures that we don't place an abi_tag attribute on +// virtual functions. This can happen by mistakenly applying a macro like +// _LIBCPP_HIDE_FROM_ABI on a virtual function. +// +// The problem is that arm64e pointer authentication extensions use the mangled +// name of the function to sign the function pointer in the vtable, which means +// that the ABI tag effectively influences how the pointers are signed. +// +// This can lead to PAC failures when passing an object that holds one of these +// pointers in its vtable across an ABI boundary if the two sides have been compiled +// with different versions of libc++: one side will sign the pointer using one function +// mangling (with one ABI tag), and the other side will authenticate the pointer expecting +// it to have a different mangled name due to the ABI tag being different, which will crash. +// +// This test ensures that we don't re-introduce this issue in the code base. + +namespace libcpp { +abi_tag_on_virtual::abi_tag_on_virtual(llvm::StringRef name, clang::tidy::ClangTidyContext* context) + : clang::tidy::ClangTidyCheck(name, context) {} + +void abi_tag_on_virtual::registerMatchers(clang::ast_matchers::MatchFinder* finder) { + using namespace clang::ast_matchers; + finder->addMatcher(cxxMethodDecl(isVirtual(), hasAttr(clang::attr::AbiTag)).bind("abi_tag_on_virtual"), this); +} + +void abi_tag_on_virtual::check(const clang::ast_matchers::MatchFinder::MatchResult& result) { + if (const auto* call = result.Nodes.getNodeAs("abi_tag_on_virtual"); call != nullptr) { + diag(call->getBeginLoc(), + "_LIBCPP_HIDE_FROM_ABI should not be used on virtual functions to avoid problems with pointer authentication. " + "Use _LIBCPP_HIDE_FROM_ABI_VIRTUAL instead."); + } +} +} // namespace libcpp diff --git a/libcxx/test/tools/clang_tidy_checks/hide_from_abi.hpp b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.hpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.hpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" + +namespace libcpp { +class hide_from_abi : public clang::tidy::ClangTidyCheck { +public: + hide_from_abi(llvm::StringRef, clang::tidy::ClangTidyContext*); + void registerMatchers(clang::ast_matchers::MatchFinder*) override; + void check(const clang::ast_matchers::MatchFinder::MatchResult&) override; +}; +} // namespace libcpp diff --git a/libcxx/test/tools/clang_tidy_checks/hide_from_abi.cpp b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" +#include "clang-tidy/ClangTidyModuleRegistry.h" + +#include "hide_from_abi.hpp" + +namespace libcpp { +hide_from_abi::hide_from_abi(llvm::StringRef name, clang::tidy::ClangTidyContext* context) + : clang::tidy::ClangTidyCheck(name, context) {} + +void hide_from_abi::registerMatchers(clang::ast_matchers::MatchFinder* finder) { + using namespace clang::ast_matchers; + finder->addMatcher( + functionDecl( + unless(anyOf( + hasName("__introsort"), + hasName("__inplace_merge"), + hasName("__libcpp_snprintf_l"), + hasName("__libcpp_asprintf_l"), + hasName("__libcpp_sscanf_l"), + hasName("__tree_sub_invariant"), + hasName("__stable_sort_move"), + hasName("__stable_sort"), + hasName("__stable_partition"), + hasName("__lock_first"), + hasName("__stable_partition_impl"), + hasAttr(clang::attr::Visibility), + hasAttr(clang::attr::AbiTag), + cxxMethodDecl(), // We have explicitly instantiated classes and some of their methods don't have these attributes + isDeleted(), + isConsteval())), + isDefinition()) + .bind("missing_hide_from_abi"), + this); +} + +void hide_from_abi::check(const clang::ast_matchers::MatchFinder::MatchResult& result) { + if (const auto* call = result.Nodes.getNodeAs("missing_hide_from_abi"); call != nullptr) { + diag(call->getBeginLoc(), "_LIBCPP_HIDE_FROM_ABI is missing"); + } +} +} // namespace libcpp diff --git a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp --- a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp +++ b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp @@ -8,6 +8,9 @@ #include "clang-tidy/ClangTidyModule.h" #include "clang-tidy/ClangTidyModuleRegistry.h" + +#include "abi_tag_on_virtual.hpp" +#include "hide_from_abi.hpp" #include "robust_against_adl.hpp" #include "qualify_declval.hpp" @@ -15,6 +18,8 @@ class LibcxxTestModule : public clang::tidy::ClangTidyModule { public: void addCheckFactories(clang::tidy::ClangTidyCheckFactories& check_factories) override { + check_factories.registerCheck("libcpp-avoid-abi-tag-on-virtual"); + check_factories.registerCheck("libcpp-hide-from-abi"); check_factories.registerCheck("libcpp-robust-against-adl"); check_factories.registerCheck("libcpp-qualify-declval"); } diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -159,9 +159,6 @@ Feature(name='has-clang-tidy', when=lambda cfg: _getSuitableClangTidy(cfg) is not None, actions=[AddSubstitution('%{clang-tidy}', lambda cfg: _getSuitableClangTidy(cfg))]), - Feature(name='has-clang-query', - when=lambda cfg: runScriptExitCode(cfg, ['clang-query-15 --version']) == 0, - actions=[AddSubstitution('%{clang-query}', 'clang-query-15')]), Feature(name='apple-clang', when=_isAppleClang), Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isAppleClang),