llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Oliver Hunt (ojhunt) <details> <summary>Changes</summary> A number of builtins report some variation of "this type is compatibile with some bitwise equivalent operation", but this is not true for address discriminated values. We had address a number of cases, but not all of them. This PR corrects the remaining builtins. Fixes #<!-- -->154394 --- Full diff: https://github.com/llvm/llvm-project/pull/154490.diff 5 Files Affected: - (modified) clang/include/clang/AST/ASTContext.h (+6-6) - (modified) clang/lib/AST/ASTContext.cpp (+3-3) - (modified) clang/lib/AST/DeclCXX.cpp (+6) - (modified) clang/lib/AST/Type.cpp (+13) - (added) clang/test/SemaCXX/ptrauth-type-traits.cpp (+143) ``````````diff diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 7c2566a09665d..d5944c19b1c15 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -640,7 +640,7 @@ class ASTContext : public RefCountedBase<ASTContext> { /// contain data that is address discriminated. This includes /// implicitly authenticated values like vtable pointers, as well as /// explicitly qualified fields. - bool containsAddressDiscriminatedPointerAuth(QualType T) { + bool containsAddressDiscriminatedPointerAuth(QualType T) const { if (!isPointerAuthenticationAvailable()) return false; return findPointerAuthContent(T) != PointerAuthContent::None; @@ -654,8 +654,8 @@ class ASTContext : public RefCountedBase<ASTContext> { bool containsNonRelocatablePointerAuth(QualType T) { if (!isPointerAuthenticationAvailable()) return false; - return findPointerAuthContent(T) == - PointerAuthContent::AddressDiscriminatedData; + return findPointerAuthContent(T) != + PointerAuthContent::None; } private: @@ -673,8 +673,8 @@ class ASTContext : public RefCountedBase<ASTContext> { bool isPointerAuthenticationAvailable() const { return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; } - PointerAuthContent findPointerAuthContent(QualType T); - llvm::DenseMap<const RecordDecl *, PointerAuthContent> + PointerAuthContent findPointerAuthContent(QualType T) const; + mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent> RecordContainsAddressDiscriminatedPointerAuth; ImportDecl *FirstLocalImport = nullptr; @@ -3720,7 +3720,7 @@ OPT_LIST(V) /// Resolve the root record to be used to derive the vtable pointer /// authentication policy for the specified record. const CXXRecordDecl * - baseForVTableAuthentication(const CXXRecordDecl *ThisClass); + baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const; bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl, StringRef MangledName); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2f2685495a8f1..69c1489eef76b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1708,7 +1708,7 @@ void ASTContext::setRelocationInfoForCXXRecord( } static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication( - ASTContext &Context, const CXXRecordDecl *Class) { + const ASTContext &Context, const CXXRecordDecl *Class) { if (!Class->isPolymorphic()) return false; const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class); @@ -1723,7 +1723,7 @@ static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication( return AddressDiscrimination == AuthAttr::AddressDiscrimination; } -ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) { +ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) const { assert(isPointerAuthenticationAvailable()); T = T.getCanonicalType(); @@ -15175,7 +15175,7 @@ StringRef ASTContext::getCUIDHash() const { } const CXXRecordDecl * -ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) { +ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const { assert(ThisClass); assert(ThisClass->isPolymorphic()); const CXXRecordDecl *PrimaryBase = ThisClass; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 50b1a1d000090..5b032cb44ba76 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1438,6 +1438,12 @@ void CXXRecordDecl::addedMember(Decl *D) { data().StructuralIfLiteral = false; } + if (!data().HasTrivialSpecialMembers && T.hasAddressDiscriminatedPointerAuth()) { + // Address discriminated fields mean that a class is no longer + // standard layout. + data().HasTrivialSpecialMembers = true; + } + // C++14 [meta.unary.prop]p4: // T is a class type [...] with [...] no non-static data members other // than subobjects of zero size diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5fbf1999ed725..1071a372162aa 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2771,6 +2771,11 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return false; QualType CanonicalType = getTypePtr()->CanonicalType; + + // Any type that is, or contains, address discriminated data is non-POD + if (CanonicalType.hasAddressDiscriminatedPointerAuth())// Context.containsAddressDiscriminatedPointerAuth(*this)) + return false; + switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: @@ -2829,6 +2834,10 @@ bool QualType::isTrivialType(const ASTContext &Context) const { if (CanonicalType->isDependentType()) return false; + // Any type that is, or contains, address discriminated data is non-POD + if (CanonicalType.hasAddressDiscriminatedPointerAuth()) // Context.containsAddressDiscriminatedPointerAuth(CanonicalType)) + return false; + // C++0x [basic.types]p9: // Scalar types, trivial class types, arrays of such types, and // cv-qualified versions of these types are collectively called trivial @@ -3179,6 +3188,10 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { if (BaseTy->isIncompleteType()) return false; + // Any type that is, or contains, address discriminated data is non-POD + if (getCanonicalType().hasAddressDiscriminatedPointerAuth()) // Context.containsAddressDiscriminatedPointerAuth(*this)) + return false; + // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; diff --git a/clang/test/SemaCXX/ptrauth-type-traits.cpp b/clang/test/SemaCXX/ptrauth-type-traits.cpp new file mode 100644 index 0000000000000..602ac3790a557 --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-type-traits.cpp @@ -0,0 +1,143 @@ +// RUN: %clang_cc1 -triple arm64 -std=c++26 -Wno-deprecated-builtins \ +// RUN: -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple arm64-apple-darwin -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -std=c++26 -Wno-deprecated-builtins \ +// RUN: -fsyntax-only -verify %s + +// expected-no-diagnostics + +#ifdef __PTRAUTH__ + +#define NonAddressDiscriminatedVTablePtrAttr \ + [[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]] +#define AddressDiscriminatedVTablePtrAttr \ + [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, no_extra_discrimination)]] +#define ADDR_DISC_ENABLED true +#else +#define NonAddressDiscriminatedVTablePtrAttr +#define AddressDiscriminatedVTablePtrAttr +#define ADDR_DISC_ENABLED false +#define __ptrauth(...) +#endif + + +typedef int* __ptrauth(1,1,1) AddressDiscriminatedPtr; +typedef __UINT64_TYPE__ __ptrauth(1,1,1) AddressDiscriminatedInt64; +struct AddressDiscriminatedFields { + AddressDiscriminatedPtr ptr; +}; +struct RelocatableAddressDiscriminatedFields trivially_relocatable_if_eligible { + AddressDiscriminatedPtr ptr; +}; +struct AddressDiscriminatedFieldInBaseClass : AddressDiscriminatedFields { + void *newfield; +}; + +struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr { + virtual ~NonAddressDiscriminatedVTablePtr(); + void *i; +}; + +struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr2 { + virtual ~NonAddressDiscriminatedVTablePtr2(); + void *j; +}; + +struct NonAddressDiscriminatedVTablePtrAttr RelocatableNonAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible { + virtual ~RelocatableNonAddressDiscriminatedVTablePtr(); + void *i; +}; + +struct NonAddressDiscriminatedVTablePtrAttr RelocatableNonAddressDiscriminatedVTablePtr2 trivially_relocatable_if_eligible { + virtual ~RelocatableNonAddressDiscriminatedVTablePtr2(); + void *j; +}; + +struct AddressDiscriminatedVTablePtrAttr AddressDiscriminatedVTablePtr { + virtual ~AddressDiscriminatedVTablePtr(); + void *k; +}; + +struct AddressDiscriminatedVTablePtrAttr RelocatableAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible { + virtual ~RelocatableAddressDiscriminatedVTablePtr(); + void *k; +}; + +struct NoAddressDiscriminatedBaseClasses : NonAddressDiscriminatedVTablePtr, + NonAddressDiscriminatedVTablePtr2 { + void *l; +}; + +struct RelocatableNoAddressDiscriminatedBaseClasses trivially_relocatable_if_eligible : + NonAddressDiscriminatedVTablePtr, + NonAddressDiscriminatedVTablePtr2 { + void *l; +}; + +struct AddressDiscriminatedPrimaryBase : AddressDiscriminatedVTablePtr, + NonAddressDiscriminatedVTablePtr { + void *l; +}; +struct AddressDiscriminatedSecondaryBase : NonAddressDiscriminatedVTablePtr, + AddressDiscriminatedVTablePtr { + void *l; +}; + +struct RelocatableAddressDiscriminatedPrimaryBase : RelocatableAddressDiscriminatedVTablePtr, + RelocatableNonAddressDiscriminatedVTablePtr { + void *l; +}; +struct RelocatableAddressDiscriminatedSecondaryBase : RelocatableNonAddressDiscriminatedVTablePtr, + RelocatableAddressDiscriminatedVTablePtr { + void *l; +}; +struct EmbdeddedAddressDiscriminatedPolymorphicClass { + AddressDiscriminatedVTablePtr field; +}; +struct RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass trivially_relocatable_if_eligible { + AddressDiscriminatedVTablePtr field; +}; + +#define ASSERT_BUILTIN_EQUALS(Expression, Predicate, Info) \ + static_assert((Expression) == (([](bool Polymorphic, bool AddrDisc, bool Relocatable, bool HasNonstandardLayout){ return (Predicate); })Info), #Expression); + //, #Expression " did not match " #Predicate); + + +#define TEST_BUILTINS(Builtin, Predicate) \ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPtr), Predicate, (false, ADDR_DISC_ENABLED, true, false)) \ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedInt64), Predicate, (false, ADDR_DISC_ENABLED, true, false))\ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFields), Predicate, (false, ADDR_DISC_ENABLED, true, false))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedFields), Predicate, (false, ADDR_DISC_ENABLED, true, false))\ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFieldInBaseClass), Predicate, (false, ADDR_DISC_ENABLED, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr), Predicate, (true, false, false, false))\ + ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr2), Predicate, (true, false, false, false))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr), Predicate, (true, false, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr2), Predicate, (true, false, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedVTablePtr), Predicate, (true, ADDR_DISC_ENABLED, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedVTablePtr), Predicate, (true, ADDR_DISC_ENABLED, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(NoAddressDiscriminatedBaseClasses), Predicate, (true, false, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNoAddressDiscriminatedBaseClasses), Predicate, (true, false, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPrimaryBase), Predicate, (true, ADDR_DISC_ENABLED, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedSecondaryBase), Predicate, (true, ADDR_DISC_ENABLED, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedPrimaryBase), Predicate, (true, ADDR_DISC_ENABLED, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedSecondaryBase), Predicate, (true, ADDR_DISC_ENABLED, true, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(EmbdeddedAddressDiscriminatedPolymorphicClass), Predicate, (true, ADDR_DISC_ENABLED, false, true))\ + ASSERT_BUILTIN_EQUALS(Builtin(RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass), Predicate, (true, ADDR_DISC_ENABLED, false, true)) + +TEST_BUILTINS(__is_pod, !(Polymorphic || AddrDisc || HasNonstandardLayout)) +TEST_BUILTINS(__is_standard_layout, !(Polymorphic || HasNonstandardLayout)) +TEST_BUILTINS(__has_trivial_move_constructor, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__has_trivial_copy, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__has_trivial_assign, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__has_trivial_move_assign, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__is_trivial, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__is_trivially_relocatable, !((Polymorphic) || AddrDisc)) +TEST_BUILTINS(__builtin_is_cpp_trivially_relocatable, !((Polymorphic && !Relocatable) || AddrDisc)) +TEST_BUILTINS(__builtin_is_replaceable, !(Polymorphic || AddrDisc)) +TEST_BUILTINS(__is_bitwise_cloneable, !AddrDisc); + +#define ASSIGNABLE_WRAPPER(Type) __is_trivially_assignable(Type&, Type) +TEST_BUILTINS(ASSIGNABLE_WRAPPER, !(Polymorphic || AddrDisc)) `````````` </details> https://github.com/llvm/llvm-project/pull/154490 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits