https://github.com/chbessonova updated https://github.com/llvm/llvm-project/pull/205808
>From 44b5b71d9e349b119d4841ccad09fce7624f6e5c Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Fri, 19 Jun 2026 18:08:22 +0200 Subject: [PATCH 1/7] [PAC][clang] Implement address/type discrimination for VTT vtable pointers Add support for address and type discrimination for vtable pointers stored in VTTs under the `-fptrauth-vtt-vtable-pointer-discrimination` option. This option is not enabled by default on any target and works in combination with `-fptrauth-vtable-pointer-address-discrimination` and/or `-fptrauth-vtable-pointer-type-discrimination`. Explicit user control over the signing schema for VTT entries is not currently supported. For address discrimination, the address of the corresponding VTT entry is used as the discriminator. The type discriminator is computed similarly to the one used for vtable pointers stored in objects, but is based on the vtable type rather than its primary base. To distinguish VTT entries from object vtable pointers, the discriminator is derived from the vtable mangling with an appended `_VTT` suffix. --- clang/include/clang/AST/ASTContext.h | 4 +- clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Options/Options.td | 2 + clang/lib/AST/ASTContext.cpp | 5 +- clang/lib/CodeGen/CGPointerAuth.cpp | 30 ++++-- clang/lib/CodeGen/CGVTT.cpp | 27 +++-- clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/CodeGen/CodeGenModule.h | 14 +-- clang/lib/CodeGen/ItaniumCXXABI.cpp | 10 +- clang/lib/Driver/ToolChains/Clang.cpp | 3 + clang/lib/Driver/ToolChains/Linux.cpp | 5 + clang/lib/Frontend/CompilerInvocation.cpp | 15 ++- .../test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp | 102 ++++++++++++++++++ clang/test/Driver/aarch64-ptrauth.c | 14 ++- clang/test/Preprocessor/ptrauth_feature.c | 33 ++++-- 16 files changed, 216 insertions(+), 53 deletions(-) create mode 100644 clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 763039e690dec..6a5846174554c 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1515,8 +1515,8 @@ class ASTContext : public RefCountedBase<ASTContext> { /// Return the "other" discriminator used for the pointer auth schema used for /// vtable pointers in instances of the requested type. - uint16_t - getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD); + uint16_t getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD, + bool IsVTTEntry = false); /// Return the "other" type-specific discriminator for the given type. uint16_t getPointerAuthTypeDiscriminator(QualType T); diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index f0a9c4889ea2d..cfd5bf69f938c 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -156,6 +156,7 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination) +FEATURE(ptrauth_vtt_vtable_pointer_discrimination, LangOpts.PointerAuthVTTVTPtrDiscrimination) FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination) FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls) FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthBlockDescriptorPointers) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 3d63b9677e4df..da4662e0b7902 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -126,6 +126,7 @@ LANGOPT(PointerAuthIndirectGotos, 1, 0, NotCompatible, "indirect gotos pointer a LANGOPT(PointerAuthAuthTraps, 1, 0, NotCompatible, "pointer authentication failure traps") LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, NotCompatible, "incorporate address discrimination in authenticated vtable pointers") LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, NotCompatible, "incorporate type discrimination in authenticated vtable pointers") +LANGOPT(PointerAuthVTTVTPtrDiscrimination, 1, 0, NotCompatible, "incorporate discrimination in authenticated vtable pointers in VTTs") LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, NotCompatible, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info") LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0, Benign, "Use type discrimination when signing function pointers") diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 1478624265f79..8053636717327 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5061,6 +5061,8 @@ defm ptrauth_vtable_pointer_address_discrimination : OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">; defm ptrauth_vtable_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">; +defm ptrauth_vtt_vtable_pointer_discrimination : + OptInCC1FFlag<"ptrauth-vtt-vtable-pointer-discrimination", "Apply the same vtable pointer discrimination scheme to VTT entries as to object vtable pointers">; defm ptrauth_type_info_vtable_pointer_discrimination : OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">; defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination", diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 02a3f88431f58..e91afe67d7f5e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3366,13 +3366,16 @@ QualType ASTContext::removeAddrSpaceQualType(QualType T) const { } uint16_t -ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) { +ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD, + bool IsVTTEntry) { assert(RD->isPolymorphic() && "Attempted to get vtable pointer discriminator on a monomorphic type"); std::unique_ptr<MangleContext> MC(createMangleContext()); SmallString<256> Str; llvm::raw_svector_ostream Out(Str); MC->mangleCXXVTable(RD, Out); + if (IsVTTEntry) + Out << "_VTT"; return llvm::getPointerAuthStableSipHash(Str); } diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 28d3289dfe04f..0fbc889836399 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -561,18 +561,24 @@ llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD, } std::optional<PointerAuthQualifier> -CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) { - auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers; +CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass, + bool IsVTTEntry) { + auto DefaultAuthentication = + IsVTTEntry ? getCodeGenOpts().PointerAuth.CXXVTTVTablePointers + : getCodeGenOpts().PointerAuth.CXXVTablePointers; if (!DefaultAuthentication) return std::nullopt; const CXXRecordDecl *PrimaryBase = Context.baseForVTableAuthentication(ThisClass); + const CXXRecordDecl *TypeDiscriminatorClass = + IsVTTEntry ? ThisClass : PrimaryBase; unsigned Key = DefaultAuthentication.getKey(); bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated(); auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination(); unsigned TypeBasedDiscriminator = - Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase); + Context.getPointerAuthVTablePointerDiscriminator(TypeDiscriminatorClass, + IsVTTEntry); unsigned Discriminator; if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) { Discriminator = TypeBasedDiscriminator; @@ -583,8 +589,11 @@ CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) { assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None); Discriminator = 0; } - if (auto ExplicitAuthentication = - PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) { + auto ExplicitAuthentication = + PrimaryBase->getAttr<VTablePointerAuthenticationAttr>(); + + // TODO: enable explicit authentication path for VTT vtable entries. + if (!IsVTTEntry && ExplicitAuthentication) { auto ExplicitAddressDiscrimination = ExplicitAuthentication->getAddressDiscrimination(); auto ExplicitDiscriminator = @@ -642,11 +651,12 @@ CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { return Authentication; } -std::optional<CGPointerAuthInfo> -CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF, - const CXXRecordDecl *Record, - llvm::Value *StorageAddress) { - auto Authentication = getVTablePointerAuthentication(Record); +std::optional<CGPointerAuthInfo> CodeGenModule::getVTablePointerAuthInfo( + CodeGenFunction *CGF, const CXXRecordDecl *Record, + llvm::Value *StorageAddress, bool IsVTTEntry) { + auto Authentication = IsVTTEntry + ? computeVTPointerAuthentication(Record, IsVTTEntry) + : getVTablePointerAuthentication(Record); if (!Authentication) return std::nullopt; diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp index 989a07d09d50e..caf51d10a4080 100644 --- a/clang/lib/CodeGen/CGVTT.cpp +++ b/clang/lib/CodeGen/CGVTT.cpp @@ -55,18 +55,17 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, } SmallVector<llvm::Constant *, 8> VTTComponents; - for (const VTTComponent *i = Builder.getVTTComponents().begin(), - *e = Builder.getVTTComponents().end(); i != e; ++i) { - const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex]; - llvm::GlobalVariable *VTable = VTables[i->VTableIndex]; + for (const auto &[Idx, C] : llvm::enumerate(Builder.getVTTComponents())) { + const VTTVTable &VTTVT = Builder.getVTTVTables()[C.VTableIndex]; + llvm::GlobalVariable *VTable = VTables[C.VTableIndex]; VTableLayout::AddressPointLocation AddressPoint; if (VTTVT.getBase() == RD) { // Just get the address point for the regular vtable. AddressPoint = getItaniumVTableContext().getVTableLayout(RD).getAddressPoint( - i->VTableBase); + C.VTableBase); } else { - AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase); + AddressPoint = VTableAddressPoints[C.VTableIndex].lookup(C.VTableBase); assert(AddressPoint.AddressPointIndex != 0 && "Did not find ctor vtable address point!"); } @@ -91,11 +90,17 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr( VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, InRange); - if (const auto &Schema = - CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) - Init = CGM.getConstantSignedPointer(Init, Schema, nullptr, GlobalDecl(), - QualType()); - + if (auto PAuthQual = CGM.computeVTPointerAuthentication( + VTTVT.getBase(), /*IsVTTEntry=*/true)) { + llvm::Constant *Address = nullptr; + if (PAuthQual->isAddressDiscriminated()) + Address = llvm::ConstantExpr::getGetElementPtr( + VTT->getType(), VTT, llvm::ConstantInt::get(CGM.Int32Ty, Idx)); + auto *Discriminator = llvm::ConstantInt::get( + CGM.IntPtrTy, PAuthQual->getExtraDiscriminator()); + Init = CGM.getConstantSignedPointer(Init, PAuthQual->getKey(), Address, + Discriminator); + } VTTComponents.push_back(Init); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 3fc9052adb87b..22d9962fb3f49 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4669,6 +4669,9 @@ class CodeGenFunction : public CodeGenTypeCache { /// Create the discriminator from the storage address and the entity hash. llvm::Value *EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress, llvm::Value *Discriminator); + CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &Schema, + llvm::Value *StorageAddress, + llvm::ConstantInt *Discriminator); CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &Schema, llvm::Value *StorageAddress, GlobalDecl SchemaDecl, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 54b08b588dfde..8cabc3fd283da 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -719,8 +719,6 @@ class CodeGenModule : public CodeGenTypeCache { llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>> VTablePtrAuthInfos; - std::optional<PointerAuthQualifier> - computeVTPointerAuthentication(const CXXRecordDecl *ThisClass); AtomicOptions AtomicOpts; @@ -1161,14 +1159,18 @@ class CodeGenModule : public CodeGenTypeCache { GlobalDecl SchemaDecl, QualType SchemaType); uint16_t getPointerAuthDeclDiscriminator(GlobalDecl GD); - std::optional<CGPointerAuthInfo> - getVTablePointerAuthInfo(CodeGenFunction *Context, - const CXXRecordDecl *Record, - llvm::Value *StorageAddress); + + std::optional<CGPointerAuthInfo> getVTablePointerAuthInfo( + CodeGenFunction *Context, const CXXRecordDecl *Record, + llvm::Value *StorageAddress, bool IsVTTEntry = false); std::optional<PointerAuthQualifier> getVTablePointerAuthentication(const CXXRecordDecl *thisClass); + std::optional<PointerAuthQualifier> + computeVTPointerAuthentication(const CXXRecordDecl *ThisClass, + bool IsVTTEntry = false); + CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD); // Return whether RTTI information should be emitted for this target. diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5c5fefe32c06c..624ac1138e6a9 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -29,6 +29,7 @@ #include "clang/AST/Mangle.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" +#include "clang/Basic/PointerAuthOptions.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" @@ -2231,13 +2232,10 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, CGF.getPointerAlign()); - if (auto &Schema = CGF.CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) { - CGPointerAuthInfo PointerAuth = CGF.EmitPointerAuthInfo(Schema, VTT, - GlobalDecl(), - QualType()); - AP = CGF.EmitPointerAuthAuth(PointerAuth, AP); + if (auto PointerAuth = CGM.getVTablePointerAuthInfo(&CGF, VTableClass, VTT, + /*IsVTTEntry=*/true)) { + AP = CGF.EmitPointerAuthAuth(*PointerAuth, AP); } - return AP; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 94f9a26aac39f..b265e4c9db88a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1745,6 +1745,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Args.addOptInFlag( CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination, options::OPT_fno_ptrauth_vtable_pointer_type_discrimination); + Args.addOptInFlag( + CmdArgs, options::OPT_fptrauth_vtt_vtable_pointer_discrimination, + options::OPT_fno_ptrauth_vtt_vtable_pointer_discrimination); Args.addOptInFlag( CmdArgs, options::OPT_fptrauth_type_info_vtable_pointer_discrimination, options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 1ab385a9ea001..89af9847e5ae5 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -520,6 +520,11 @@ static void handlePAuthABI(const Driver &D, const ArgList &DriverArgs, options::OPT_fno_ptrauth_vtable_pointer_type_discrimination)) CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination"); + if (!DriverArgs.hasArg( + options::OPT_fptrauth_vtt_vtable_pointer_discrimination, + options::OPT_fno_ptrauth_vtt_vtable_pointer_discrimination)) + CC1Args.push_back("-fptrauth-vtt-vtable-pointer-discrimination"); + if (!DriverArgs.hasArg( options::OPT_fptrauth_type_info_vtable_pointer_discrimination, options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination)) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 6562cb3a9b135..56b39dc672aa6 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1476,8 +1476,15 @@ void CompilerInvocation::setDefaultPointerAuthOptions( Opts.CXXTypeInfoVTablePointer = PointerAuthSchema(Key::ASDA, false, Discrimination::None); - Opts.CXXVTTVTablePointers = - PointerAuthSchema(Key::ASDA, false, Discrimination::None); + if (LangOpts.PointerAuthVTTVTPtrDiscrimination) + Opts.CXXVTTVTablePointers = PointerAuthSchema( + Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination, + LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type + : Discrimination::None); + else + Opts.CXXVTTVTablePointers = + PointerAuthSchema(Key::ASDA, false, Discrimination::None); + Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers = PointerAuthSchema(Key::ASIA, true, Discrimination::Decl); Opts.CXXMemberFunctionPointers = @@ -3588,6 +3595,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination); if (Opts.PointerAuthVTPtrTypeDiscrimination) GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination); + if (Opts.PointerAuthVTTVTPtrDiscrimination) + GenerateArg(Consumer, OPT_fptrauth_vtt_vtable_pointer_discrimination); if (Opts.PointerAuthTypeInfoVTPtrDiscrimination) GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination); if (Opts.PointerAuthFunctionTypeDiscrimination) @@ -3621,6 +3630,8 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination); Opts.PointerAuthVTPtrTypeDiscrimination = Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination); + Opts.PointerAuthVTTVTPtrDiscrimination = + Args.hasArg(OPT_fptrauth_vtt_vtable_pointer_discrimination); Opts.PointerAuthTypeInfoVTPtrDiscrimination = Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination); Opts.PointerAuthFunctionTypeDiscrimination = diff --git a/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp b/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp new file mode 100644 index 0000000000000..1c344d5247eaf --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp @@ -0,0 +1,102 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest -fptrauth-calls -disable-llvm-passes \ +// RUN: -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,DEFAULT %s +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest -fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \ +// RUN: -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,DEFAULT %s +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest -fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,ADDRESS %s +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest -fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,TYPE %s +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest -fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,ADDRESSTYPE %s + +// CHECK: @_ZTT1D = linkonce_odr unnamed_addr constant [4 x ptr] [ +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2), +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2), +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2), +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2)] + +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 0, ptr @_ZTT1D), +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr (ptr, ptr @_ZTT1D, i32 1)), +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr (ptr, ptr @_ZTT1D, i32 2)), +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr (ptr, ptr @_ZTT1D, i32 3))] + +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820), +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118), +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118), +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820)] + +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820, ptr @_ZTT1D), +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr getelementptr (ptr, ptr @_ZTT1D, i32 1)), +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr getelementptr (ptr, ptr @_ZTT1D, i32 2)), +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820, ptr getelementptr (ptr, ptr @_ZTT1D, i32 3))] + +// CHECK: @_ZTT1A = linkonce_odr unnamed_addr constant [2 x ptr] [ +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2), +// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2)] + +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr @_ZTT1A), +// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr (ptr, ptr @_ZTT1A, i32 1))] + +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118), +// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118)] + +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr @_ZTT1A), +// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr getelementptr (ptr, ptr @_ZTT1A, i32 1))] + +// CHECK-LABEL: @_ZN1AC2Ev +// CHECK: %vtt.addr = alloca ptr, align 8 +// CHECK: store ptr %vtt, ptr %vtt.addr, align 8 +// CHECK: [[VTT:%.*]] = load ptr, ptr %vtt.addr, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTT]], align 8 +// ADDRESS: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64 +// ADDRESSTYPE: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64 +// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTABLE_ADDR]], i64 49118) +// CHECK: [[VTABLEi64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// DEFAULT: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 0) +// ADDRESS: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 [[VTABLE_ADDR]]) +// TYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 49118) +// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 [[DISC]]) + +// CHECK: [[VTTOFFSET:%.*]] = getelementptr inbounds ptr, ptr [[VTT]], i64 1 +// CHECK: [[VTABLE2:%.*]] = load ptr, ptr [[VTTOFFSET]], align 8 +// ADDRESS: [[VTABLE2_ADDR:%.*]] = ptrtoint ptr [[VTTOFFSET]] to i64 +// ADDRESSTYPE: [[VTABLE2_ADDR:%.*]] = ptrtoint ptr [[VTTOFFSET]] to i64 +// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTABLE2_ADDR]], i64 49118) +// CHECK: [[VTABLE2i64:%.*]] = ptrtoint ptr [[VTABLE2]] to i64 +// DEFAULT: call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 0) +// ADDRESS: call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 [[VTABLE2_ADDR]]) +// TYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 49118) +// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 [[DISC]]) + +// CHECK-LABEL: @_ZN1DC2Ev +// CHECK: %vtt.addr = alloca ptr, align 8 +// CHECK: store ptr %vtt, ptr %vtt.addr, align 8 +// CHECK: [[VTT:%.*]] = load ptr, ptr %vtt.addr, align 8 +// CHECK: [[VTTOFFSET:%.*]] = getelementptr inbounds ptr, ptr [[VTT]], i64 1 +// CHECK: call void @_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1, ptr noundef [[VTTOFFSET]]) +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTT]], align 8 +// ADDRESS: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64 +// ADDRESSTYPE: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64 +// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTABLE_ADDR]], i64 820) +// CHECK: [[VTABLEi64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// DEFAULT: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 0) +// ADDRESS: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 [[VTABLE_ADDR]]) +// TYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 820) +// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 [[DISC]]) + +struct V { + virtual void f(); +}; + +struct A : virtual V { + A(); +}; + +struct D : A { + D(); +}; + +A::A() {} +D::D() {} diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index b503acaba28ee..1fc6d224c500d 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -12,6 +12,7 @@ // RUN: -fno-ptrauth-auth-traps -fptrauth-auth-traps \ // RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-vtt-vtable-pointer-discrimination -fptrauth-vtt-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fptrauth-type-info-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \ // RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \ @@ -26,6 +27,7 @@ // RUN: -fno-ptrauth-auth-traps -fptrauth-auth-traps \ // RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-vtt-vtable-pointer-discrimination -fptrauth-vtt-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fptrauth-type-info-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \ // RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \ @@ -33,7 +35,7 @@ // RUN: -fno-ptrauth-elf-got -fptrauth-elf-got \ // RUN: -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \ // RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL-LINUX-PAUTHABI -// ALL-LINUX-PAUTHABI: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" "-fptrauth-elf-got"{{.*}} "-faarch64-jump-table-hardening" +// ALL-LINUX-PAUTHABI: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-vtt-vtable-pointer-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" "-fptrauth-elf-got"{{.*}} "-faarch64-jump-table-hardening" // RUN: %clang -### -c --target=aarch64-linux \ // RUN: -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \ @@ -59,12 +61,13 @@ // RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=PAUTHABI1 --implicit-check-not='"-fptrauth-function-pointer-type-discrimination"' // PAUTHABI1: "-cc1"{{.*}} "-triple" "aarch64-unknown-linux-pauthtest" -// PAUTHABI1-SAME: "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" "-fptrauth-elf-got" "-faarch64-jump-table-hardening" +// PAUTHABI1-SAME: "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-vtt-vtable-pointer-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" "-fptrauth-elf-got" "-faarch64-jump-table-hardening" // PAUTHABI1-SAME: "-target-abi" "pauthtest" // RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -fno-ptrauth-intrinsics \ // RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \ // RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-vtt-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fno-ptrauth-indirect-gotos \ // RUN: -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination \ // RUN: -fno-ptrauth-elf-got -fno-aarch64-jump-table-hardening %s 2>&1 | \ @@ -72,6 +75,7 @@ // RUN: %clang -### -c --target=aarch64-linux-pauthtest -fno-ptrauth-intrinsics \ // RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \ // RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-vtt-vtable-pointer-discrimination \ // RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fno-ptrauth-indirect-gotos \ // RUN: -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination \ // RUN: -fno-ptrauth-elf-got -fno-aarch64-jump-table-hardening %s 2>&1 | \ @@ -94,14 +98,16 @@ //// Non-pauthtest ABI. // RUN: not %clang -### -c --target=aarch64-linux -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \ // RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-type-info-vtable-pointer-discrimination -fptrauth-indirect-gotos -fptrauth-init-fini \ -// RUN: -fptrauth-init-fini-address-discrimination -fptrauth-elf-got %s 2>&1 | FileCheck %s --check-prefix=ERR1 +// RUN: -fptrauth-vtt-vtable-pointer-discrimination -fptrauth-type-info-vtable-pointer-discrimination \ +// RUN: -fptrauth-indirect-gotos -fptrauth-init-fini -fptrauth-init-fini-address-discrimination \ +// RUN: -fptrauth-elf-got %s 2>&1 | FileCheck %s --check-prefix=ERR1 // ERR1: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-vtt-vtable-pointer-discrimination' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-type-info-vtable-pointer-discrimination' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-indirect-gotos' for target '{{.*}}' // ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}' diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index cebea4188415f..c187dd0160355 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -2,37 +2,40 @@ //// For example, -fptrauth-init-fini will not affect codegen without -fptrauth-calls, but the preprocessor feature would be set anyway. // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-intrinsics | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-calls | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-returns | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,RETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,RETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-vtable-pointer-address-discrimination | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT + +// RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-vtt-vtable-pointer-discrimination | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,VTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-vtable-pointer-type-discrimination | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-type-info-vtable-pointer-discrimination | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,TYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,TYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-function-pointer-type-discrimination | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,FUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,FUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,INITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,INITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-init-fini-address-discrimination | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,INITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,INITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-indirect-gotos | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,GOTOS,NOELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,GOTOS,NOELFGOT,NOVTT // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-elf-got | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,ELFGOT +// RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,ELFGOT,NOVTT #if defined(__PTRAUTH__) // INTRIN: has_ptrauth_intrinsics @@ -83,6 +86,14 @@ void has_ptrauth_vtable_pointer_type_discrimination() {} void no_ptrauth_vtable_pointer_type_discrimination() {} #endif +#if __has_feature(ptrauth_vtt_vtable_pointer_discrimination) +// VTT: has_ptrauth_vtt_vtable_pointer_discrimination +void has_ptrauth_vtt_vtable_pointer_discrimination() {} +#else +// NOVTT: no_ptrauth_vtt_vtable_pointer_discrimination +void no_ptrauth_vtt_vtable_pointer_discrimination() {} +#endif + #if __has_feature(ptrauth_type_info_vtable_pointer_discrimination) // TYPE_INFO_DISCR: has_ptrauth_type_info_vtable_pointer_discrimination void has_ptrauth_type_info_vtable_pointer_discrimination() {} >From f305d129678d770e5540a195feec15c725b75dc0 Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Wed, 15 Jul 2026 23:57:27 +0200 Subject: [PATCH 2/7] Address review comments --- clang/include/clang/AST/ASTContext.h | 4 ++-- clang/lib/AST/ItaniumMangle.cpp | 3 ++- clang/lib/CodeGen/CGExprConstant.cpp | 4 +++- clang/lib/CodeGen/CGPointerAuth.cpp | 22 +++++++++++----------- clang/lib/CodeGen/CGVTT.cpp | 5 +++-- clang/lib/CodeGen/CodeGenModule.h | 8 ++++---- clang/lib/CodeGen/ItaniumCXXABI.cpp | 4 ++-- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 6a5846174554c..01634da901740 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1514,9 +1514,9 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType removeAddrSpaceQualType(QualType T) const; /// Return the "other" discriminator used for the pointer auth schema used for - /// vtable pointers in instances of the requested type. + /// vtable pointers using the given discriminator type. uint16_t getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD, - bool IsVTTEntry = false); + bool IsVTTEntry); /// Return the "other" type-specific discriminator for the given type. uint16_t getPointerAuthTypeDiscriminator(QualType T); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index f8e6b898be250..7639de7d47565 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -7366,7 +7366,8 @@ static void mangleOverrideDiscrimination(CXXNameMangler &Mangler, const CXXRecordDecl *PtrauthClassRD = Context.baseForVTableAuthentication(ThisRD); unsigned TypedDiscriminator = - Context.getPointerAuthVTablePointerDiscriminator(ThisRD); + Context.getPointerAuthVTablePointerDiscriminator(ThisRD, + /*IsVTTEntry=*/false); Mangler.mangleVendorQualifier("__vtptrauth"); auto &ManglerStream = Mangler.getStream(); ManglerStream << "I"; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 257de0145855b..bea75d7e6fadf 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -854,7 +854,9 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, llvm::Constant *VTableAddressPoint = CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset), VTableClass); - if (auto Authentication = CGM.getVTablePointerAuthentication(CD)) { + if (auto Authentication = + CGM.getVTablePointerAuthentication(CD, + /*IsVTTEntry=*/false)) { VTableAddressPoint = Emitter.tryEmitConstantSignedPointer( VTableAddressPoint, *Authentication); if (!VTableAddressPoint) diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 0fbc889836399..38f95eff242b1 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -636,27 +636,27 @@ CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass, } std::optional<PointerAuthQualifier> -CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { +CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record, + bool IsVTTEntry) { if (!Record->getDefinition() || !Record->isPolymorphic()) return std::nullopt; - auto Existing = VTablePtrAuthInfos.find(Record); - std::optional<PointerAuthQualifier> Authentication; - if (Existing != VTablePtrAuthInfos.end()) { - Authentication = Existing->getSecond(); - } else { - Authentication = computeVTPointerAuthentication(Record); - VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); + if (!IsVTTEntry) { + auto Existing = VTablePtrAuthInfos.find(Record); + if (Existing != VTablePtrAuthInfos.end()) + return Existing->getSecond(); } + std::optional<PointerAuthQualifier> Authentication = + computeVTPointerAuthentication(Record, IsVTTEntry); + if (!IsVTTEntry) + VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); return Authentication; } std::optional<CGPointerAuthInfo> CodeGenModule::getVTablePointerAuthInfo( CodeGenFunction *CGF, const CXXRecordDecl *Record, llvm::Value *StorageAddress, bool IsVTTEntry) { - auto Authentication = IsVTTEntry - ? computeVTPointerAuthentication(Record, IsVTTEntry) - : getVTablePointerAuthentication(Record); + auto Authentication = getVTablePointerAuthentication(Record, IsVTTEntry); if (!Authentication) return std::nullopt; diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp index caf51d10a4080..bfc873ec59f52 100644 --- a/clang/lib/CodeGen/CGVTT.cpp +++ b/clang/lib/CodeGen/CGVTT.cpp @@ -90,8 +90,9 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr( VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, InRange); - if (auto PAuthQual = CGM.computeVTPointerAuthentication( - VTTVT.getBase(), /*IsVTTEntry=*/true)) { + if (auto PAuthQual = + CGM.getVTablePointerAuthentication(VTTVT.getBase(), + /*IsVTTEntry=*/true)) { llvm::Constant *Address = nullptr; if (PAuthQual->isAddressDiscriminated()) Address = llvm::ConstantExpr::getGetElementPtr( diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 8cabc3fd283da..49892b6202192 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -719,6 +719,9 @@ class CodeGenModule : public CodeGenTypeCache { llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>> VTablePtrAuthInfos; + std::optional<PointerAuthQualifier> + computeVTPointerAuthentication(const CXXRecordDecl *ThisClass, + bool IsVTTEntry); AtomicOptions AtomicOpts; @@ -1165,10 +1168,7 @@ class CodeGenModule : public CodeGenTypeCache { llvm::Value *StorageAddress, bool IsVTTEntry = false); std::optional<PointerAuthQualifier> - getVTablePointerAuthentication(const CXXRecordDecl *thisClass); - - std::optional<PointerAuthQualifier> - computeVTPointerAuthentication(const CXXRecordDecl *ThisClass, + getVTablePointerAuthentication(const CXXRecordDecl *thisClass, bool IsVTTEntry = false); CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 624ac1138e6a9..616b086c7d411 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2233,9 +2233,9 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CGF.getPointerAlign()); if (auto PointerAuth = CGM.getVTablePointerAuthInfo(&CGF, VTableClass, VTT, - /*IsVTTEntry=*/true)) { + /*IsVTTEntry=*/true)) AP = CGF.EmitPointerAuthAuth(*PointerAuth, AP); - } + return AP; } >From 1d3eb18f528893d156fab757c6be6fb2ab3d1614 Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Tue, 21 Jul 2026 14:54:54 +0200 Subject: [PATCH 3/7] Address review comment --- clang/lib/CodeGen/CGPointerAuth.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 38f95eff242b1..6889899107266 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -641,15 +641,16 @@ CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record, if (!Record->getDefinition() || !Record->isPolymorphic()) return std::nullopt; - if (!IsVTTEntry) { - auto Existing = VTablePtrAuthInfos.find(Record); - if (Existing != VTablePtrAuthInfos.end()) - return Existing->getSecond(); - } + if (IsVTTEntry) + return computeVTPointerAuthentication(Record, IsVTTEntry); + + auto Existing = VTablePtrAuthInfos.find(Record); + if (Existing != VTablePtrAuthInfos.end()) + return Existing->getSecond(); + std::optional<PointerAuthQualifier> Authentication = computeVTPointerAuthentication(Record, IsVTTEntry); - if (!IsVTTEntry) - VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); + VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); return Authentication; } >From ad99ca08027566819c086d8b945f446451f175da Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Tue, 28 Jul 2026 11:43:35 +0200 Subject: [PATCH 4/7] Add documentation --- clang/docs/PointerAuthentication.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/clang/docs/PointerAuthentication.md b/clang/docs/PointerAuthentication.md index fde6d00915369..375c76c2d3785 100644 --- a/clang/docs/PointerAuthentication.md +++ b/clang/docs/PointerAuthentication.md @@ -1389,6 +1389,17 @@ override the schema used for the v-table pointer of the base type of polymorphic class hierarchy. This attribute permits the configuration of the key, address diversity mode, and any extra constant discriminator to be used. +Like object v-table pointers, pointers to virtual tables stored in VTTs are +signed with the `DA` key. By default, no additional address or type +discrimination is applied. When `-fptrauth-vtt-vtable-pointer-discrimination` +is enabled, they are additionally discriminated by address and/or type, +as controlled by the `-fptrauth-vtable-pointer-{address,type}-discrimination` +options. Address discrimination uses the address of the corresponding VTT entry. +Type discrimination uses the string hash (see [`ptrauth_string_discriminator`](#ptrauth-string-discriminator)) +of the mangled v-table identifier of the current class with an appended `_VTT` +suffix. Unlike object v-table pointers, explicit schema customization for VTT +entries is currently not supported. + Virtual functions in a C++ virtual table are signed with the `IA` key, address diversity, and a constant discriminator equal to the string hash (see [`ptrauth_string_discriminator`](#ptrauth-string-discriminator)) of the mangled name of the function which >From e08b8627d57f61b1ad5d1682613e5660b757d4a8 Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Tue, 28 Jul 2026 11:52:15 +0200 Subject: [PATCH 5/7] Give '_VTT' a name and pull it out --- clang/include/clang/Basic/PointerAuthOptions.h | 4 ++++ clang/lib/AST/ASTContext.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index 2aa8d70088dbc..17ae1d2835dda 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -54,6 +54,10 @@ constexpr unsigned PointerAuthKeyNone = -1; /// the vtable type discriminator for classes derived from std::type_info. constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA; +// Type discriminator suffix to be added to a mangled v-table identifier to +// ensure that VTT vtable pointer entries get distinct type discriminators. +constexpr llvm::StringLiteral VTTVTablePointerDiscriminatorSuffix = "_VTT"; + class PointerAuthSchema { public: enum class Kind : unsigned { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e91afe67d7f5e..99c1d3f8c6fed 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3370,12 +3370,13 @@ ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD, bool IsVTTEntry) { assert(RD->isPolymorphic() && "Attempted to get vtable pointer discriminator on a monomorphic type"); + std::unique_ptr<MangleContext> MC(createMangleContext()); SmallString<256> Str; llvm::raw_svector_ostream Out(Str); MC->mangleCXXVTable(RD, Out); if (IsVTTEntry) - Out << "_VTT"; + Out << VTTVTablePointerDiscriminatorSuffix; return llvm::getPointerAuthStableSipHash(Str); } >From 0d48a67c43abb0979cf75118caab421cc75a0a13 Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Tue, 28 Jul 2026 20:23:17 +0200 Subject: [PATCH 6/7] Fix formatting --- clang/lib/CodeGen/CGExprConstant.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index bea75d7e6fadf..48e80910ce577 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -854,9 +854,9 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, llvm::Constant *VTableAddressPoint = CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset), VTableClass); - if (auto Authentication = - CGM.getVTablePointerAuthentication(CD, - /*IsVTTEntry=*/false)) { + if (auto Authentication = + CGM.getVTablePointerAuthentication(CD, + /*IsVTTEntry=*/false)) { VTableAddressPoint = Emitter.tryEmitConstantSignedPointer( VTableAddressPoint, *Authentication); if (!VTableAddressPoint) >From 27b2ccf1b12e517e0e865484024b06a0f53742c4 Mon Sep 17 00:00:00 2001 From: Kristina Bessonova <[email protected]> Date: Tue, 4 Aug 2026 13:49:36 +0200 Subject: [PATCH 7/7] Add a release note --- clang/docs/ReleaseNotes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index f0d34731e0e50..e420cf71d729e 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -457,6 +457,10 @@ features cannot lower the translation-unit ABI level; #### Arm and AArch64 Support +- Added support for pointer authentication discrimination of C++ virtual table + pointers stored in VTTs via the `-fptrauth-vtt-vtable-pointer-discrimination` + option. + #### Android Support #### Windows Support _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
