diff --git a/libcxx/docs/TestingLibcxx.rst b/libcxx/docs/TestingLibcxx.rst index 9f185479c2590..283646aef4c76 100644 --- a/libcxx/docs/TestingLibcxx.rst +++ b/libcxx/docs/TestingLibcxx.rst @@ -98,8 +98,7 @@ Additional tools 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 index 2ecddcf6e3ae1..91d38aac0df03 100644 --- a/libcxx/include/__memory_resource/unsynchronized_pool_resource.h +++ b/libcxx/include/__memory_resource/unsynchronized_pool_resource.h @@ -85,7 +85,7 @@ class _LIBCPP_TYPE_VIS unsynchronized_pool_resource : public memory_resource { 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 index c3b9b022b6e3a..0000000000000 --- 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 index 27f54b08feccb..0000000000000 --- 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 index ffa465aa61bee..0000000000000 --- 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 index d287a09323969..0000000000000 --- 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 index f5539a9303eba..adceee2d8b3c7 100644 --- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt +++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt @@ -6,11 +6,13 @@ set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) 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.cpp b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.cpp new file mode 100644 index 0000000000000..f1866179a3b68 --- /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/abi_tag_on_virtual.hpp b/libcxx/test/tools/clang_tidy_checks/abi_tag_on_virtual.hpp new file mode 100644 index 0000000000000..9a8d8210113ab --- /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/hide_from_abi.cpp b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.cpp new file mode 100644 index 0000000000000..9ae253670133b --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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( + // These functions can't be marked `[[gnu::always_inline]]` for various reasons, + // so we can't mark them `_LIBCPP_HIDE_FROM_ABI`. These functions are ignored in + // all namespaces. Checking the qualified name is a lot harder and these names + // should result in very few (if any) false-negatives. This is also just a + // temporary work-around until we can mark functions as HIDE_FROM_ABI without + // having to add `[[gnu::always_inline]]` with GCC. + hasAnyName("__introsort", + "__inplace_merge", + "__libcpp_snprintf_l", + "__libcpp_asprintf_l", + "__libcpp_sscanf_l", + "__tree_sub_invariant", + "__stable_sort_move", + "__stable_sort", + "__stable_partition", + "__lock_first", + "__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/hide_from_abi.hpp b/libcxx/test/tools/clang_tidy_checks/hide_from_abi.hpp new file mode 100644 index 0000000000000..d73b510a4a906 --- /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/libcpp_module.cpp b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp index 60d200c5fcb0b..f1dfbf563959e 100644 --- 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 @@ namespace { 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/ci/Dockerfile b/libcxx/utils/ci/Dockerfile index 67c94bd88f09d..2a2e8e58b0ba5 100644 --- a/libcxx/utils/ci/Dockerfile +++ b/libcxx/utils/ci/Dockerfile @@ -91,9 +91,6 @@ RUN apt-get update && apt-get install -y llvm-$(($LLVM_HEAD_VERSION - 1))-dev # TODO LLVM16 Don't install llvm-16-dev explicitly RUN apt-get update && apt-get install -y llvm-16-dev libclang-16-dev -# Install clang-tools -RUN apt-get update && apt-get install -y clang-tools-$(($LLVM_HEAD_VERSION - 1)) clang-tools-$LLVM_HEAD_VERSION - # Install the most recent GCC, like clang install the previous version as a transition. ENV GCC_LATEST_VERSION=12 RUN apt-get update && apt install -y gcc-$((GCC_LATEST_VERSION - 1)) g++-$((GCC_LATEST_VERSION - 1)) diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py index 52c96026e87e3..c2745b918369d 100644 --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -159,9 +159,6 @@ def _getSuitableClangTidy(cfg): 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),