https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/147899
>From 3b0a91c3d4a4ae8ec7980d2201d94f59746fb769 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 9 Jul 2025 17:30:48 -0700 Subject: [PATCH] [clang][ObjC][PAC] Add ptrauth protections to objective-c This PR introduces the use of pointer authentication to objective-c[++]. This includes: * __ptrauth qualifier support for ivars * protection of isa and super fields * protection of SEL typed ivars * protection of class_ro_t data * protection of methodlist pointers and content --- clang/include/clang/AST/ASTContext.h | 2 + clang/include/clang/Basic/Features.def | 6 + clang/include/clang/Basic/LangOptions.def | 5 + .../include/clang/Basic/PointerAuthOptions.h | 35 +++++ clang/include/clang/Driver/Options.td | 3 + clang/lib/AST/ASTContext.cpp | 11 ++ clang/lib/CodeGen/CGBlocks.cpp | 21 ++- clang/lib/CodeGen/CGObjC.cpp | 52 ++++++- clang/lib/CodeGen/CGObjCMac.cpp | 94 +++++++++---- clang/lib/CodeGen/CodeGenModule.cpp | 4 +- clang/lib/CodeGen/ConstantInitBuilder.cpp | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 7 + clang/lib/Frontend/CompilerInvocation.cpp | 34 +++++ clang/lib/Headers/ptrauth.h | 57 ++++++++ clang/lib/Sema/SemaDeclObjC.cpp | 8 ++ clang/lib/Sema/SemaObjCProperty.cpp | 9 ++ clang/test/CodeGenObjC/arc.m | 8 +- .../test/CodeGenObjC/matrix-type-operators.m | 10 +- .../test/CodeGenObjC/ptrauth-attr-exception.m | 17 +++ clang/test/CodeGenObjC/ptrauth-block-isa.m | 40 ++++++ clang/test/CodeGenObjC/ptrauth-class-ro.m | 24 ++++ clang/test/CodeGenObjC/ptrauth-class.m | 103 ++++++++++++++ .../ptrauth-objc-interface-selector.m | 130 ++++++++++++++++++ .../test/CodeGenObjC/ptrauth-objc-isa-super.m | 57 ++++++++ .../ptrauth-objc-method-list-pointer.m | 17 +++ .../CodeGenObjC/ptrauth-property-backing.m | 80 +++++++++++ .../ptrauth-objc-interface-selector.mm | 90 ++++++++++++ clang/test/SemaObjC/ptrauth-pointers.m | 46 +++++++ clang/test/SemaObjC/ptrauth-qualifier.m | 39 +++++- 29 files changed, 969 insertions(+), 42 deletions(-) create mode 100644 clang/test/CodeGenObjC/ptrauth-attr-exception.m create mode 100644 clang/test/CodeGenObjC/ptrauth-block-isa.m create mode 100644 clang/test/CodeGenObjC/ptrauth-class-ro.m create mode 100644 clang/test/CodeGenObjC/ptrauth-class.m create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-isa-super.m create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m create mode 100644 clang/test/CodeGenObjC/ptrauth-property-backing.m create mode 100644 clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm create mode 100644 clang/test/SemaObjC/ptrauth-pointers.m diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2b9cd035623cc..8c27728c404dd 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2300,6 +2300,8 @@ class ASTContext : public RefCountedBase<ASTContext> { return getTypeDeclType(getObjCSelDecl()); } + PointerAuthQualifier getObjCMemberSelTypePtrAuth(); + /// Retrieve the typedef declaration corresponding to the predefined /// Objective-C 'Class' type. TypedefDecl *getObjCClassDecl() const; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 14bff8a68846d..c2e677e31e5a0 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -119,6 +119,12 @@ FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos) FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini) FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination) FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT) + +FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa) +FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel) +FEATURE(ptrauth_objc_signable_class, true) +FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls) + EXTENSION(swiftcc, PP.getTargetInfo().checkCallingConvention(CC_Swift) == clang::TargetInfo::CCCR_OK) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 72321c204ce96..852188de18654 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -133,6 +133,11 @@ LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, NotCompatible, LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from GOT") LANGOPT(AArch64JumpTableHardening, 1, 0, NotCompatible, "use hardened lowering for jump-table dispatch") +LANGOPT(PointerAuthObjcIsa, 1, 0, NotCompatible, "authentication of isa and super pointers in ObjC instances") +LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of SEL fields of ObjC interfaces") +LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication key for SEL fields of ObjC interfaces") +LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer authentication") + LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes") LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes") diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index a3a3e50bcde5d..fb6dddf3ae9ce 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -27,6 +27,26 @@ namespace clang { /// .fini_array. The value is ptrauth_string_discriminator("init_fini") constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4; +/// Constant discriminator to be used with method list pointers. The value is +/// ptrauth_string_discriminator("method_list_t") +constexpr uint16_t MethodListPointerConstantDiscriminator = 0xC310; + +/// Constant discriminator to be used with objective-c isa pointers. The value +/// is ptrauth_string_discriminator("isa") +constexpr uint16_t IsaPointerConstantDiscriminator = 0x6AE1; + +/// Constant discriminator to be used with objective-c superclass pointers. +/// The value is ptrauth_string_discriminator("objc_class:superclass") +constexpr uint16_t SuperPointerConstantDiscriminator = 0xB5AB; + +/// Constant discriminator to be used with objective-c sel pointers. The value +/// is ptrauth_string_discriminator("sel") +constexpr uint16_t SelPointerConstantDiscriminator = 0x57c2; + +/// Constant discriminator to be used with objective-c class_ro_t pointers. +/// The value is ptrauth_string_discriminator("class_data_bits") +constexpr uint16_t ClassROConstantDiscriminator = 0x61F8; + constexpr unsigned PointerAuthKeyNone = -1; /// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546 @@ -202,6 +222,21 @@ struct PointerAuthOptions { /// The ABI for function addresses in .init_array and .fini_array PointerAuthSchema InitFiniPointers; + + /// The ABI for Objective-C method lists. + PointerAuthSchema ObjCMethodListFunctionPointers; + + /// The ABI for a reference to an Objective-C method list in _class_ro_t. + PointerAuthSchema ObjCMethodListPointer; + + /// The ABI for Objective-C isa pointers. + PointerAuthSchema ObjCIsaPointers; + + /// The ABI for Objective-C superclass pointers. + PointerAuthSchema ObjCSuperPointers; + + /// The ABI for Objective-C class_ro_t pointers. + PointerAuthSchema ObjCClassROPointers; }; } // end namespace clang diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 77379f1130149..e2b347246f7ab 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4498,6 +4498,9 @@ defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini "Enable address discrimination of function pointers in init/fini arrays">; defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">; defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">; +defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and authentication of Objective-C object's 'isa' field">; +defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", "Enable signing and authentication of Objective-C object's 'SEL' fields">; +defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable signing and authentication for ObjC class_ro pointers">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 679812adcdf12..0499a81cd5231 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -9783,6 +9783,17 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const { return ObjCProtocolClassDecl; } +PointerAuthQualifier ASTContext::getObjCMemberSelTypePtrAuth() { + if (!getLangOpts().PointerAuthObjcInterfaceSel) + return PointerAuthQualifier(); + return PointerAuthQualifier::Create( + getLangOpts().PointerAuthObjcInterfaceSelKey, + /*isAddressDiscriminated=*/true, SelPointerConstantDiscriminator, + PointerAuthenticationMode::SignAndAuth, + /*isIsaPointer=*/false, + /*authenticatesNullValues=*/false); +} + //===----------------------------------------------------------------------===// // __builtin_va_list Construction Functions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index f3ddf7bf9a463..1aba841eb5fc2 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -853,9 +853,24 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { offset += size; index++; }; + auto addSignedHeaderField = + [&](llvm::Value *Value, const PointerAuthSchema &Schema, + GlobalDecl Decl, QualType Type, CharUnits Size, const Twine &Name) { + auto StorageAddress = projectField(index, Name); + if (Schema) { + auto AuthInfo = EmitPointerAuthInfo( + Schema, StorageAddress.emitRawPointer(*this), Decl, Type); + Value = EmitPointerAuthSign(AuthInfo, Value); + } + Builder.CreateStore(Value, StorageAddress); + offset += Size; + index++; + }; if (!IsOpenCL) { - addHeaderField(isa, getPointerSize(), "block.isa"); + addSignedHeaderField( + isa, CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, GlobalDecl(), + QualType(), getPointerSize(), "block.isa"); addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()), getIntSize(), "block.flags"); addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(), @@ -1285,7 +1300,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, if (IsWindows) fields.addNullPointer(CGM.Int8PtrPtrTy); else - fields.add(CGM.getNSConcreteGlobalBlock()); + fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(), + CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, + GlobalDecl(), QualType()); // __flags BlockFlags flags = BLOCK_IS_GLOBAL; diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 6f87444d3f672..24b6ce7c1c70d 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1193,16 +1193,23 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, ivarAddr = ivarAddr.withElementType(bitcastType); llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load"); load->setAtomic(llvm::AtomicOrdering::Unordered); + llvm::Value *ivarVal = load; + if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) { + CGPointerAuthInfo SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr); + CGPointerAuthInfo TargetInfo = + CGM.getPointerAuthInfoForType(getterMethod->getReturnType()); + ivarVal = emitPointerAuthResign(ivarVal, ivar->getType(), SrcInfo, + TargetInfo, /*isKnownNonNull=*/false); + } // Store that value into the return address. Doing this with a // bitcast is likely to produce some pretty ugly IR, but it's not // the *most* terrible thing in the world. llvm::Type *retTy = ConvertType(getterMethod->getReturnType()); uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy); - llvm::Value *ivarVal = load; if (ivarSize > retTySize) { bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize); - ivarVal = Builder.CreateTrunc(load, bitcastType); + ivarVal = Builder.CreateTrunc(ivarVal, bitcastType); } Builder.CreateStore(ivarVal, ReturnValue.withElementType(bitcastType)); @@ -1214,6 +1221,16 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, case PropertyImplStrategy::GetSetProperty: { llvm::FunctionCallee getPropertyFn = CGM.getObjCRuntime().GetPropertyGetFunction(); + + if (ivar->getType().getPointerAuth()) { + // This currently cannot be hit, but if we ever allow objc pointers + // to be signed, this will become possible. Reaching here would require + // a copy, weak, etc property backed by an authenticated pointer. + CGM.ErrorUnsupported(propImpl, + "Obj-C getter requiring pointer authentication"); + return; + } + if (!getPropertyFn) { CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy"); return; @@ -1269,7 +1286,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0); QualType ivarType = ivar->getType(); - switch (getEvaluationKind(ivarType)) { + auto EvaluationKind = getEvaluationKind(ivarType); + assert(!ivarType.getPointerAuth() || EvaluationKind == TEK_Scalar); + switch (EvaluationKind) { case TEK_Complex: { ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation()); EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType), @@ -1287,6 +1306,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, case TEK_Scalar: { llvm::Value *value; if (propType->isReferenceType()) { + if (ivarType.getPointerAuth()) { + CGM.ErrorUnsupported(propImpl, + "Obj-C getter for authenticated reference type"); + return; + } value = LV.getAddress().emitRawPointer(*this); } else { // We want to load and autoreleaseReturnValue ARC __weak ivars. @@ -1300,7 +1324,19 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, // Otherwise we want to do a simple load, suppressing the // final autorelease. } else { - value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal(); + if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) { + Address ivarAddr = LV.getAddress(); + llvm::LoadInst *LoadInst = Builder.CreateLoad(ivarAddr, "load"); + llvm::Value *Load = LoadInst; + auto SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr); + auto TargetInfo = + CGM.getPointerAuthInfoForType(getterMethod->getReturnType()); + Load = emitPointerAuthResign(Load, ivarType, SrcInfo, TargetInfo, + /*isKnownNonNull=*/false); + value = Load; + } else + value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal(); + AutoreleaseResult = false; } @@ -1490,6 +1526,14 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, llvm::Value *load = Builder.CreateLoad(argAddr); + if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) { + QualType PropertyType = propImpl->getPropertyDecl()->getType(); + CGPointerAuthInfo SrcInfo = CGM.getPointerAuthInfoForType(PropertyType); + CGPointerAuthInfo TargetInfo = EmitPointerAuthInfo(PAQ, ivarAddr); + load = emitPointerAuthResign(load, ivar->getType(), SrcInfo, TargetInfo, + /*isKnownNonNull=*/false); + } + // Perform an atomic store. There are no memory ordering requirements. llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr); store->setAtomic(llvm::AtomicOrdering::Unordered); diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index a52c92cdbc83b..8e71a576552d3 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1935,7 +1935,9 @@ CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) { auto Fields = Builder.beginStruct(NSConstantStringType); // Class pointer. - Fields.add(Class); + Fields.addSignedPointer(Class, + CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, + GlobalDecl(), QualType()); // String pointer. llvm::Constant *C = @@ -4975,10 +4977,7 @@ enum ImageInfoFlags { eImageInfo_GCOnly = (1 << 2), eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache. - // A flag indicating that the module has no instances of a @synthesize of a - // superclass variable. This flag used to be consumed by the runtime to work - // around miscompile by gcc. - eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang. + eImageInfo_SignedClassRO = (1 << 4), // Reused (was _CorrectedSynthesize) eImageInfo_ImageIsSimulated = (1 << 5), eImageInfo_ClassProperties = (1 << 6) }; @@ -5036,6 +5035,17 @@ void CGObjCCommonMac::EmitImageInfo() { // Indicate whether we are generating class properties. Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties", eImageInfo_ClassProperties); + + // Indicate whether we want enforcement of pointer signing for class_ro_t + // pointers. + if (CGM.getLangOpts().PointerAuthObjcClassROPointers) + Mod.addModuleFlag(llvm::Module::Error, + "Objective-C Enforce ClassRO Pointer Signing", + eImageInfo_SignedClassRO); + else + Mod.addModuleFlag(llvm::Module::Error, + "Objective-C Enforce ClassRO Pointer Signing", + llvm::ConstantInt::get(Int8Ty, 0)); } // struct objc_module { @@ -6223,11 +6233,19 @@ llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassRoTInitializer( methods.push_back(MD); } - values.add(emitMethodList(ID->getObjCRuntimeNameAsString(), - (flags & NonFragileABI_Class_Meta) - ? MethodListType::ClassMethods - : MethodListType::InstanceMethods, - methods)); + llvm::Constant *MethListPtr = emitMethodList( + ID->getObjCRuntimeNameAsString(), + (flags & NonFragileABI_Class_Meta) ? MethodListType::ClassMethods + : MethodListType::InstanceMethods, + methods); + + const PointerAuthSchema &MethListSchema = + CGM.getCodeGenOpts().PointerAuth.ObjCMethodListPointer; + if (!MethListPtr->isNullValue()) + values.addSignedPointer(MethListPtr, MethListSchema, GlobalDecl(), + QualType()); + else + values.add(MethListPtr); const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); @@ -6275,15 +6293,20 @@ llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassObject( bool HiddenVisibility) { ConstantInitBuilder builder(CGM); auto values = builder.beginStruct(ObjCTypes.ClassnfABITy); - values.add(IsAGV); - if (SuperClassGV) { - values.add(SuperClassGV); - } else { + const PointerAuthOptions &PointerAuthOpts = CGM.getCodeGenOpts().PointerAuth; + values.addSignedPointer(IsAGV, PointerAuthOpts.ObjCIsaPointers, GlobalDecl(), + QualType()); + if (SuperClassGV) + values.addSignedPointer(SuperClassGV, PointerAuthOpts.ObjCSuperPointers, + GlobalDecl(), QualType()); + else values.addNullPointer(ObjCTypes.ClassnfABIPtrTy); - } + values.add(ObjCEmptyCacheVar); values.add(ObjCEmptyVtableVar); - values.add(ClassRoGV); + + values.addSignedPointer(ClassRoGV, PointerAuthOpts.ObjCClassROPointers, + GlobalDecl(), QualType()); llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>( GetClassGlobal(CI, isMetaclass, ForDefinition)); @@ -6543,15 +6566,27 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } } - auto instanceMethodList = emitMethodList( + llvm::Constant *InstanceMethodList = emitMethodList( listName, MethodListType::CategoryInstanceMethods, instanceMethods); - auto classMethodList = emitMethodList( + const PointerAuthSchema &MethListSchema = + CGM.getCodeGenOpts().PointerAuth.ObjCMethodListPointer; + if (!InstanceMethodList->isNullValue()) + values.addSignedPointer(InstanceMethodList, MethListSchema, GlobalDecl(), + QualType()); + else + values.add(InstanceMethodList); + + llvm::Constant *ClassMethodList = emitMethodList( listName, MethodListType::CategoryClassMethods, classMethods); - values.add(instanceMethodList); - values.add(classMethodList); + if (!ClassMethodList->isNullValue()) + values.addSignedPointer(ClassMethodList, MethListSchema, GlobalDecl(), + QualType()); + else + values.add(ClassMethodList); + // Keep track of whether we have actual metadata to emit. bool isEmptyCategory = - instanceMethodList->isNullValue() && classMethodList->isNullValue(); + InstanceMethodList->isNullValue() && ClassMethodList->isNullValue(); const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); @@ -6629,7 +6664,13 @@ void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder, } else { llvm::Function *fn = GetMethodDefinition(MD); assert(fn && "no definition for method?"); - method.add(fn); + if (const PointerAuthSchema &Schema = + CGM.getCodeGenOpts().PointerAuth.ObjCMethodListFunctionPointers) { + llvm::Constant *Bitcast = + llvm::ConstantExpr::getBitCast(fn, ObjCTypes.Int8PtrProgramASTy); + method.addSignedPointer(Bitcast, Schema, GlobalDecl(), QualType()); + } else + method.add(fn); } method.finishAndAddTo(builder); @@ -7672,10 +7713,15 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, } llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2); + llvm::Constant *VTablePtr = llvm::ConstantExpr::getInBoundsGetElementPtr( + VTableGV->getValueType(), VTableGV, VTableIdx); + ConstantInitBuilder builder(CGM); auto values = builder.beginStruct(ObjCTypes.EHTypeTy); - values.add(llvm::ConstantExpr::getInBoundsGetElementPtr( - VTableGV->getValueType(), VTableGV, VTableIdx)); + const PointerAuthSchema &TypeInfoSchema = + CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer; + values.addSignedPointer(VTablePtr, TypeInfoSchema, GlobalDecl(), QualType()); + values.add(GetClassName(ClassName)); values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition)); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c8866f15745c2..678be0718be28 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6616,7 +6616,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { auto Fields = Builder.beginStruct(STy); // Class pointer. - Fields.add(cast<llvm::Constant>(CFConstantStringClassRef)); + Fields.addSignedPointer(cast<llvm::Constant>(CFConstantStringClassRef), + getCodeGenOpts().PointerAuth.ObjCIsaPointers, + GlobalDecl(), QualType()); // Flags. if (IsSwiftABI) { diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp b/clang/lib/CodeGen/ConstantInitBuilder.cpp index 7b3e7aea0f647..0f93d81c53fc7 100644 --- a/clang/lib/CodeGen/ConstantInitBuilder.cpp +++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp @@ -309,7 +309,7 @@ void ConstantAggregateBuilderBase::addSignedPointer( if (Schema.isAddressDiscriminated()) { StorageAddress = getAddrOfCurrentPosition(Pointer->getType()); } - + assert(!Pointer->isNullValue()); llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer( Pointer, Schema, StorageAddress, CalleeDecl, CalleeType); add(SignedPointer); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index b76163afc8aa4..48e327c425c24 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1746,6 +1746,13 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Args.addOptInFlag(CmdArgs, options::OPT_faarch64_jump_table_hardening, options::OPT_fno_aarch64_jump_table_hardening); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_isa, + options::OPT_fno_ptrauth_objc_isa); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_interface_sel, + options::OPT_fno_ptrauth_objc_interface_sel); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_class_ro, + options::OPT_fno_ptrauth_objc_class_ro); + if (Triple.getEnvironment() == llvm::Triple::PAuthTest) handlePAuthABI(Args, CmdArgs); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b9f75796ecc16..08cf0ae6b2c24 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1541,6 +1541,25 @@ void CompilerInvocation::setDefaultPointerAuthOptions( Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination, Discrimination::Constant, InitFiniPointerConstantDiscriminator); } + + Opts.ObjCMethodListFunctionPointers = + PointerAuthSchema(Key::ASIA, true, Discrimination::None); + Opts.ObjCMethodListPointer = + PointerAuthSchema(Key::ASDA, true, Discrimination::Constant, + MethodListPointerConstantDiscriminator); + if (LangOpts.PointerAuthObjcIsa) { + Opts.ObjCIsaPointers = + PointerAuthSchema(Key::ASDA, true, Discrimination::Constant, + IsaPointerConstantDiscriminator); + Opts.ObjCSuperPointers = + PointerAuthSchema(Key::ASDA, true, Discrimination::Constant, + SuperPointerConstantDiscriminator); + } + + if (LangOpts.PointerAuthObjcClassROPointers) + Opts.ObjCClassROPointers = + PointerAuthSchema(Key::ASDA, true, Discrimination::Constant, + ClassROConstantDiscriminator); } Opts.ReturnAddresses = LangOpts.PointerAuthReturns; Opts.AuthTraps = LangOpts.PointerAuthAuthTraps; @@ -3573,6 +3592,12 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_fptrauth_elf_got); if (Opts.AArch64JumpTableHardening) GenerateArg(Consumer, OPT_faarch64_jump_table_hardening); + if (Opts.PointerAuthObjcIsa) + GenerateArg(Consumer, OPT_fptrauth_objc_isa); + if (Opts.PointerAuthObjcInterfaceSel) + GenerateArg(Consumer, OPT_fptrauth_objc_interface_sel); + if (Opts.PointerAuthObjcClassROPointers) + GenerateArg(Consumer, OPT_fptrauth_objc_class_ro); } static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, @@ -3596,6 +3621,15 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, Opts.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got); Opts.AArch64JumpTableHardening = Args.hasArg(OPT_faarch64_jump_table_hardening); + + Opts.PointerAuthObjcIsa = Args.hasArg(OPT_fptrauth_objc_isa); + Opts.PointerAuthObjcClassROPointers = Args.hasArg(OPT_fptrauth_objc_class_ro); + Opts.PointerAuthObjcInterfaceSel = + Args.hasArg(OPT_fptrauth_objc_interface_sel); + + if (Opts.PointerAuthObjcInterfaceSel) + Opts.PointerAuthObjcInterfaceSelKey = + static_cast<unsigned>(PointerAuthSchema::ARM8_3Key::ASDB); } /// Check if input file kind and language standard are compatible. diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index d489a67c533d4..7f7d387cbdfda 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -42,6 +42,19 @@ typedef enum { The extra data is always 0. */ ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data, + /* The key used to sign metadata pointers to Objective-C method-lists. */ + ptrauth_key_method_list_pointer = ptrauth_key_asda, + + /* The key used to sign Objective-C isa and super pointers. */ + ptrauth_key_objc_isa_pointer = ptrauth_key_process_independent_data, + ptrauth_key_objc_super_pointer = ptrauth_key_process_independent_data, + + /* The key used to sign selector pointers */ + ptrauth_key_objc_sel_pointer = ptrauth_key_process_dependent_data, + + /* The key used to sign Objective-C class_ro_t pointers. */ + ptrauth_key_objc_class_ro_pointer = ptrauth_key_process_independent_data, + /* The key used to sign pointers in ELF .init_array/.fini_array. */ ptrauth_key_init_fini_pointer = ptrauth_key_process_independent_code, @@ -259,6 +272,46 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; /* The value is ptrauth_string_discriminator("init_fini") */ #define __ptrauth_init_fini_discriminator 0xd9d4 +/* Objective-C pointer auth ABI qualifiers */ +#define __ptrauth_objc_method_list_imp \ + __ptrauth(ptrauth_key_function_pointer, 1, 0) + +#if __has_feature(ptrauth_objc_method_list_pointer) +#define __ptrauth_objc_method_list_pointer \ + __ptrauth(ptrauth_key_method_list_pointer, 1, 0xC310) +#else +#define __ptrauth_objc_method_list_pointer +#endif + +#define __ptrauth_isa_discriminator 0x6AE1 +#define __ptrauth_super_discriminator 0xB5AB +#define __ptrauth_objc_isa_pointer \ + __ptrauth(ptrauth_key_objc_isa_pointer, 1, __ptrauth_isa_discriminator) +#if __has_feature(ptrauth_restricted_intptr_qualifier) +#define __ptrauth_objc_isa_uintptr \ + __ptrauth_restricted_intptr(ptrauth_key_objc_isa_pointer, 1, \ + __ptrauth_isa_discriminator) +#else +#define __ptrauth_objc_isa_uintptr \ + __ptrauth(ptrauth_key_objc_isa_pointer, 1, __ptrauth_isa_discriminator) +#endif + +#define __ptrauth_objc_super_pointer \ + __ptrauth(ptrauth_key_objc_super_pointer, 1, __ptrauth_super_discriminator) + +#define __ptrauth_objc_sel_discriminator 0x57c2 +#if __has_feature(ptrauth_objc_interface_sel) +#define __ptrauth_objc_sel \ + __ptrauth(ptrauth_key_objc_sel_pointer, 1, __ptrauth_objc_sel_discriminator) +#else +#define __ptrauth_objc_sel +#endif + +#define __ptrauth_objc_class_ro_discriminator 0x61f8 +#define __ptrauth_objc_class_ro \ + __ptrauth(ptrauth_key_objc_class_ro_pointer, 1, \ + __ptrauth_objc_class_ro_discriminator) + #else #define ptrauth_strip(__value, __key) \ @@ -331,6 +384,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; #define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ extra_discrimination...) +#define __ptrauth_objc_isa_pointer +#define __ptrauth_objc_isa_uintptr +#define __ptrauth_objc_super_pointer + #endif /* __has_feature(ptrauth_intrinsics) */ #endif /* __PTRAUTH_H */ diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 9dbc3efbca405..bbd104909956f 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -5585,6 +5585,14 @@ Decl *SemaObjC::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D); QualType T = TInfo->getType(); + ASTContext &Context = getASTContext(); + if (Context.getLangOpts().PointerAuthObjcInterfaceSel && + !T.getPointerAuth()) { + if (Context.isObjCSelType(T.getUnqualifiedType())) { + if (auto PAQ = Context.getObjCMemberSelTypePtrAuth()) + T = Context.getPointerAuthType(T, PAQ); + } + } if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 9d5106805892a..9dbb1d28aa722 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1298,6 +1298,15 @@ Decl *SemaObjC::ActOnPropertyImplDecl( } } + if (Context.getLangOpts().PointerAuthObjcInterfaceSel && + !PropertyIvarType.getPointerAuth()) { + if (Context.isObjCSelType(QualType(PropertyIvarType.getTypePtr(), 0))) { + if (auto PAQ = Context.getObjCMemberSelTypePtrAuth()) + PropertyIvarType = + Context.getPointerAuthType(PropertyIvarType, PAQ); + } + } + Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyIvarLoc,PropertyIvarLoc, PropertyIvar, PropertyIvarType, /*TInfo=*/nullptr, diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 6dbd5057314e4..57afe9c245e77 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1371,13 +1371,13 @@ void test71(void) { // CHECK: %[[T:.*]] = alloca [2 x ptr], align 16 // CHECK: %[[V0:.*]] = call ptr @llvm.objc.retain(ptr %[[A]]) // CHECK: %[[V1:.*]] = call ptr @llvm.objc.retain(ptr %[[B]]) #2 -// CHECK: %[[V3:.*]] = load ptr, ptr %[[A_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V3:.*]] = load ptr, ptr %[[A_ADDR]], align 8, !tbaa !{{[0-9]+}} // CHECK: %[[V4:.*]] = call ptr @llvm.objc.retain(ptr %[[V3]]) #2 -// CHECK: store ptr %[[V4]], ptr %[[T]], align 8, !tbaa !7 +// CHECK: store ptr %[[V4]], ptr %[[T]], align 8, !tbaa !{{[0-9]+}} // CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds ptr, ptr %[[T]], i64 1 -// CHECK: %[[V5:.*]] = load ptr, ptr %[[B_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V5:.*]] = load ptr, ptr %[[B_ADDR]], align 8, !tbaa !{{[0-9]+}} // CHECK: %[[V6:.*]] = call ptr @llvm.objc.retain(ptr %[[V5]]) #2 -// CHECK: store ptr %[[V6]], ptr %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !7 +// CHECK: store ptr %[[V6]], ptr %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !{{[0-9]+}} // CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x ptr], ptr %[[T]], i32 0, i32 0 // CHECK: %[[V7:.*]] = getelementptr inbounds ptr, ptr %[[ARRAY_BEGIN]], i64 2 diff --git a/clang/test/CodeGenObjC/matrix-type-operators.m b/clang/test/CodeGenObjC/matrix-type-operators.m index 179bb180daf90..ddd6c5f003f0a 100644 --- a/clang/test/CodeGenObjC/matrix-type-operators.m +++ b/clang/test/CodeGenObjC/matrix-type-operators.m @@ -13,11 +13,11 @@ @interface IntValue // CHECK-LABEL: @test_index_placeholders( // CHECK-NEXT: entry: // CHECK: [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8 -// CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !{{[0-9]+}} // CHECK-NEXT: [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], ptr noundef [[SEL]]) // CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 // CHECK-NEXT: [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8 -// CHECK-NEXT: [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !{{[0-9]+}} // CHECK-NEXT: [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], ptr noundef [[SEL2]]) // CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4 @@ -38,17 +38,17 @@ @interface MatrixValue // CHECK-LABEL: @test_base_and_index_placeholders( // CHECK: [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8 -// CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !{{[0-9]+}} // CHECK-NEXT: [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], ptr noundef [[SEL]]) // CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 // CHECK-NEXT: [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8 -// CHECK-NEXT: [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !{{[0-9]+}} // CHECK-NEXT: [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], ptr noundef [[SEL2]]) // CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4 // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]] // CHECK-NEXT: [[M:%.*]] = load ptr, ptr %m.addr, align 8 -// CHECK-NEXT: [[SEL3:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[SEL3:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !{{[0-9]+}} // CHECK-NEXT: [[MAT:%.*]] = call <16 x double> @objc_msgSend(ptr noundef [[M]], ptr noundef [[SEL3]]) // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]] // CHECK-NEXT: ret double [[MATEXT]] diff --git a/clang/test/CodeGenObjC/ptrauth-attr-exception.m b/clang/test/CodeGenObjC/ptrauth-attr-exception.m new file mode 100644 index 0000000000000..8c07a698ecc70 --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-attr-exception.m @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple arm64e -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s + +__attribute__((objc_root_class)) +@interface Root { + Class isa; +} +@end + +__attribute__((objc_exception)) +@interface A : Root +@end + +@implementation A +@end + +// CHECK: @"OBJC_EHTYPE_$_A" = global %struct._objc_typeinfo { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @objc_ehtype_vtable, i32 2), i32 2), ptr @OBJC_CLASS_NAME_, ptr @"OBJC_CLASS_$_A" } + //. @"OBJC_EHTYPE_$_A" = global %struct._objc_typeinfo { ptr getelementptr inbounds (ptr, ptr @objc_ehtype_vtable, i32 2), ptr @OBJC_CLASS_NAME_, ptr @"OBJC_CLASS_$_A" } diff --git a/clang/test/CodeGenObjC/ptrauth-block-isa.m b/clang/test/CodeGenObjC/ptrauth-block-isa.m new file mode 100644 index 0000000000000..c1e98c6fd9d3e --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-block-isa.m @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fptrauth-calls -fptrauth-objc-isa -fobjc-arc -fblocks -triple arm64e -emit-llvm %s -o - | FileCheck %s + +void (^globalblock)(void) = ^{}; +// CHECK: [[GLOBAL_BLOCK:@.*]] = internal constant { ptr, i32, i32, ptr, ptr } { ptr ptrauth (ptr @_NSConcreteGlobalBlock, i32 2, i64 27361, ptr [[GLOBAL_BLOCK]]), i32 1342177280, i32 0, ptr @globalblock_block_invoke, ptr @"__block_descriptor_32_e5_v8\01?0l" }, align 8 #0 + +@interface A +- (int) count; +@end + +void use_block(int (^)(void)); + +// CHECK-LABEL: define dso_local void @test_block_literal( +void test_block_literal(int i) { + // CHECK: [[I:%.*]] = alloca i32, + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align + // CHECK: [[ISAPTRADDR:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 0 + // CHECK-NEXT: [[ISAPTRADDR_I:%.*]] = ptrtoint ptr [[ISAPTRADDR]] to i64 + // CHECK-NEXT: [[ISADISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ISAPTRADDR_I]], i64 27361) + // CHECK-NEXT: [[SIGNEDISA:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @_NSConcreteStackBlock to i64), i32 2, i64 [[ISADISCRIMINATOR]]) + // CHECK-NEXT: [[SIGNEDISAPTR:%.*]] = inttoptr i64 [[SIGNEDISA]] to ptr + // CHECK-NEXT: store ptr [[SIGNEDISAPTR]], ptr [[ISAPTRADDR]] + use_block(^{return i;}); +} + +void test_conversion_helper(id); + +// CHECK-LABEL: define dso_local void @test_conversion( +void test_conversion(id a) { + // CHECK: [[A:%.*addr]] = alloca ptr + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align + // CHECK: [[ISAPTRADDR:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 0 + // CHECK-NEXT: [[ISAPTRADDR_I:%.*]] = ptrtoint ptr [[ISAPTRADDR]] to i64 + // CHECK-NEXT: [[ISADISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ISAPTRADDR_I]], i64 27361) + // CHECK-NEXT: [[SIGNEDISA:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @_NSConcreteStackBlock to i64), i32 2, i64 [[ISADISCRIMINATOR]]) + // CHECK-NEXT: [[SIGNEDISAPTR:%.*]] = inttoptr i64 [[SIGNEDISA]] to ptr + // CHECK-NEXT: store ptr [[SIGNEDISAPTR]], ptr [[ISAPTRADDR]] + test_conversion_helper(^{ + (void)a; + }); +} diff --git a/clang/test/CodeGenObjC/ptrauth-class-ro.m b/clang/test/CodeGenObjC/ptrauth-class-ro.m new file mode 100644 index 0000000000000..d4364a9b8e332 --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-class-ro.m @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fptrauth-calls -Wno-objc-root-class -fptrauth-objc-class-ro -fobjc-arc -emit-llvm -o - %s | FileCheck %s + +// CHECK: @"OBJC_CLASS_$_C" = global %struct._class_t { ptr @"OBJC_METACLASS_$_C", ptr null, ptr @_objc_empty_cache, ptr null, ptr ptrauth (ptr @"_OBJC_CLASS_RO_$_C", i32 2, i64 25080, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_CLASS_$_C", i32 0, i32 4)) }, section "__DATA, __objc_data", align 8 +// CHECK: @"OBJC_METACLASS_$_C" = global %struct._class_t { ptr @"OBJC_METACLASS_$_C", ptr @"OBJC_CLASS_$_C", ptr @_objc_empty_cache, ptr null, ptr ptrauth (ptr @"_OBJC_METACLASS_RO_$_C", i32 2, i64 25080, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_C", i32 0, i32 4)) }, section "__DATA, __objc_data", align 8 +// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"C\00", section "__TEXT,__objc_classname,cstring_literals", align 1 +// CHECK: @"_OBJC_METACLASS_RO_$_C" = internal global %struct._class_ro_t { i32 131, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8 +// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [3 x i8] c"m0\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1 +// CHECK: @"_OBJC_$_INSTANCE_METHODS_C" = internal global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr ptrauth (ptr @"\01-[C m0]", i32 0, i64 0, ptr getelementptr inbounds ({ i32, i32, [1 x %struct._objc_method] }, ptr @"_OBJC_$_INSTANCE_METHODS_C", i32 0, i32 2, i32 0, i32 2)) }] }, section "__DATA, __objc_const", align 8 +// CHECK: @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 130, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr @"_OBJC_$_INSTANCE_METHODS_C", i32 2, i64 49936, ptr getelementptr inbounds (%struct._class_ro_t, ptr @"_OBJC_CLASS_RO_$_C", i32 0, i32 5)), ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8 +// CHECK: @OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8 +// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_C"], section "__DATA,__objc_classlist,regular,no_dead_strip" + +@interface C +- (void) m0; +@end + +@implementation C +- (void)m0 {} +@end + +void test_sign_class_ro(C *c) { + [c m0]; +} diff --git a/clang/test/CodeGenObjC/ptrauth-class.m b/clang/test/CodeGenObjC/ptrauth-class.m new file mode 100644 index 0000000000000..c5ad03665f2a7 --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-class.m @@ -0,0 +1,103 @@ +// RUN: %clang_cc1 -Wno-everything -fblocks -fptrauth-intrinsics -triple arm64-apple-ios -fobjc-runtime=ios-12.2 -emit-llvm -no-enable-noundef-analysis -fobjc-arc -O2 -disable-llvm-passes -o - %s | FileCheck %s + +#if __has_feature(ptrauth_objc_signable_class) +struct TestStruct { + __ptrauth(2, 1, 1234) Class isa; +}; + +@interface TestClass { +@public + __ptrauth(2, 1, 1234) Class isa; +} +@end + +struct TestConstStruct { + __ptrauth(2, 1, 1234) const Class isa; + __ptrauth(2, 1, 1234) volatile Class visa; +}; + +@interface TestConstClass { +@public + __ptrauth(2, 1, 1234) const Class isa; + __ptrauth(2, 1, 1234) volatile Class visa; +} +@end + +// CHECK-LABEL: define void @setTestStructIsa(ptr %t, ptr %c) #0 { +void setTestStructIsa(struct TestStruct *t, Class c) { + t->isa = c; + // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[C_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: store ptr %c, ptr [[C_ADDR]], align 8 + // CHECK: [[ISA_SLOT:%.*]] = getelementptr inbounds nuw %struct.TestStruct, ptr %0, i32 0, i32 0 + // CHECK: [[C:%.*]] = load ptr, ptr %c.addr, align 8 + // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr [[ISA_SLOT]] to i64 + // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ISA_SLOT]], i64 1234) + // CHECK: [[CAST_C:%.*]] = ptrtoint ptr [[C]] to i64 + // CHECK: [[AUTHENTICATED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CAST_C]], i32 2, i64 [[BLENDED_VALUE]]) +} + +// CHECK-LABEL: define void @setTestClassIsa(ptr %t, ptr %c) #0 { +void setTestClassIsa(TestClass *t, Class c) { + t->isa = c; + // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[C_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: store ptr %c, ptr [[C_ADDR]], align 8 + // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8 + // CHECK: [[IVAR_OFFSET32:%.*]] = load i32, ptr @"OBJC_IVAR_$_TestClass.isa", align 8 + // CHECK: [[IVAR_OFFSET64:%.*]] = sext i32 [[IVAR_OFFSET32]] to i64 + // CHECK: [[ADDED_PTR:%.*]] = getelementptr inbounds i8, ptr %1, i64 [[IVAR_OFFSET64]] + // CHECK: [[C_VALUE:%.*]] = load ptr, ptr [[C_ADDR]], align 8 + // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr [[ADDED_PTR]] to i64 + // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ISA_SLOT]], i64 1234) + // CHECK: [[CAST_C_VALUE:%.*]] = ptrtoint ptr [[C_VALUE]] to i64 + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CAST_C_VALUE]], i32 2, i64 [[BLENDED_VALUE]]) +} + +// CHECK-LABEL: define ptr @getTestStructIsa(ptr %t) #0 { +Class getTestStructIsa(struct TestStruct *t) { + return t->isa; + // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[T_VALUE:%.*]] = load ptr, ptr [[T_ADDR]], align 8 + // CHECK: [[ISA_SLOT:%.*]] = getelementptr inbounds nuw %struct.TestStruct, ptr [[T_VALUE]], i32 0, i32 0 + // CHECK: [[ISA_VALUE:%.*]] = load ptr, ptr [[ISA_SLOT]], align 8 + // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr %isa to i64 + // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ISA_SLOT]], i64 1234) + // CHECK: [[CAST_ISA_VALUE:%.*]] = ptrtoint ptr [[ISA_VALUE]] to i64 + // CHECK: [[SIGNED_VALUE:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_ISA_VALUE]], i32 2, i64 [[BLENDED_VALUE]]) +} + +// CHECK-LABEL: define ptr @getTestClassIsa(ptr %t) #0 { +Class getTestClassIsa(TestClass *t) { + return t->isa; + // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8 + // CHECK: [[IVAR:%.*]] = load i32, ptr @"OBJC_IVAR_$_TestClass.isa", align 8 + // CHECK: [[IVAR_CONV:%.*]] = sext i32 [[IVAR]] to i64 + // CHECK: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[T]], i64 [[IVAR_CONV]] + // CHECK: [[LOADED_VALUE:%.*]] = load ptr, ptr [[ADD_PTR]], align 8 + // CHECK: [[INT_VALUE:%.*]] = ptrtoint ptr [[ADD_PTR]] to i64 + // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[INT_VALUE]], i64 1234) + // CHECK: [[NULL_CHECK:%.*]] = icmp ne ptr [[LOADED_VALUE]], null + // CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[LOADED_VALUE]] to i64 + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VALUE]], i32 2, i64 [[BLENDED_VALUE]]) +} + +// Just enough to verify we do actually authenticate qualified Class +// CHECK: define ptr @getTestConstClassIsa(ptr %t) #0 { +Class getTestConstClassIsa(TestConstClass *t) { + return t->isa; + // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8 + // CHECK: [[IVAR:%.*]] = load i32, ptr @"OBJC_IVAR_$_TestConstClass.isa", align 8 + // CHECK: [[IVAR_CONV:%.*]] = sext i32 [[IVAR]] to i64 + // CHECK: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[T]], i64 [[IVAR_CONV]] + // CHECK: [[LOADED_VALUE:%.*]] = load ptr, ptr [[ADD_PTR]], align 8 + // CHECK: [[INT_VALUE:%.*]] = ptrtoint ptr [[ADD_PTR]] to i64 + // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[INT_VALUE]], i64 1234) + // CHECK: [[NULL_CHECK:%.*]] = icmp ne ptr [[LOADED_VALUE]], null + // CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[LOADED_VALUE]] to i64 + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VALUE]], i32 2, i64 [[BLENDED_VALUE]]) +} + +#endif diff --git a/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m b/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m new file mode 100644 index 0000000000000..53734bb1121fa --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -O0 -Wno-objc-root-class -fptrauth-intrinsics -fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm -fptrauth-objc-interface-sel -o - %s | FileCheck --check-prefix=CHECK-AUTHENTICATED-SEL %s +// RUN: %clang_cc1 -O0 -Wno-objc-root-class -fptrauth-intrinsics -fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNAUTHENTICATED-SEL %s + +#include <ptrauth.h> +#define __ptrauth_objc_sel_override \ + __ptrauth(ptrauth_key_objc_sel_pointer, 1, 22467) + +@interface Test { +@public + SEL auto_sel; +@public + const SEL const_auto_sel; +@public + volatile SEL volatile_auto_sel; +@public + SEL __ptrauth_objc_sel_override manual; +@public + const SEL __ptrauth_objc_sel_override const_manual; +@public + volatile SEL __ptrauth_objc_sel_override volatile_manual; +@public + + SEL __ptrauth_objc_sel_override _manual_sel_property; +} + +@property SEL auto_sel_property; +@property const SEL const_auto_sel_property; +@property volatile SEL volatile_auto_sel_property; +@property SEL manual_sel_property; + +@end + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test test:]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 {{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}}) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = load volatile ptr, ptr {{%.*}}, align 8 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 {{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}}) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22467) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22467) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 {{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}}) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test auto_sel_property]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test setAuto_sel_property:]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test const_auto_sel_property]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test setConst_auto_sel_property:]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test volatile_auto_sel_property]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test setVolatile_auto_sel_property:]" +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, i32 3, i64 {{%.*}}) + +@implementation Test +- (SEL)test:(Test *)in { + _auto_sel_property = in->_auto_sel_property; + _volatile_auto_sel_property = in->_volatile_auto_sel_property; + _manual_sel_property = in->_manual_sel_property; + return _const_auto_sel_property; +} +@end + +void auto_sel(Test *out, Test *in) { + out->auto_sel = in->auto_sel; +} +// CHECK-AUTHENTICATED-SEL-LABEL: define void @auto_sel +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +// CHECK-UNAUTHENTICATED-SEL-LABEL: define void @auto_sel +SEL const_auto_sel(Test *in) { + return in->const_auto_sel; +} + +// CHECK-AUTHENTICATED-SEL-LABEL: define ptr @const_auto_sel +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64 +// CHECK-AUTHENTICATED-SEL: [[AUTHENTICATED:%.*]] = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) +// CHECK-AUTHENTICATED-SEL: [[RESULT:%.*]] = inttoptr i64 [[AUTHENTICATED]] to ptr + +void volatile_auto_sel(Test *out, Test *in) { + out->volatile_auto_sel = in->volatile_auto_sel; +} + +// CHECK-AUTHENTICATED-SEL-LABEL: define void @volatile_auto_sel +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +void manual(Test *out, Test *in) { + out->manual = in->manual; +} + +// CHECK-AUTHENTICATED-SEL-LABEL: define void @manual +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +// CHECK-UNAUTHENTICATED-SEL-LABEL: define void @manual +// CHECK-UNAUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467) +// CHECK-UNAUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-UNAUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467) +// CHECK-UNAUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-UNAUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) diff --git a/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m b/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m new file mode 100644 index 0000000000000..69fd01f28067d --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -I %S/Inputs -fptrauth-calls -fptrauth-objc-isa -triple arm64-apple-ios -emit-llvm -no-enable-noundef-analysis -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s + +#include "literal-support.h" + +#if __has_feature(objc_bool) +#define YES __objc_yes +#define NO __objc_no +#else +#define YES ((BOOL)1) +#define NO ((BOOL)0) +#endif + +@class NSString; + +// CHECK: @"OBJC_METACLASS_$_C" = global %struct._class_t { ptr ptrauth (ptr @"OBJC_METACLASS_$_Base", i32 2, i64 27361, ptr @"OBJC_METACLASS_$_C"), ptr ptrauth (ptr @"OBJC_METACLASS_$_Base", i32 2, i64 46507, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_C", i32 0, i32 1)), ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_C" } +// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_" = private global ptr @"OBJC_METACLASS_$_C" +// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [5 x i8] c"test\00" +// CHECK: @OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_ +// CHECK: @"OBJC_METACLASS_$_Base" = external global %struct._class_t +// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"C\00" +// CHECK: @OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [11 x i8] c"super_test\00" +// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"v16@0:8\00" +// CHECK: @"_OBJC_$_CLASS_METHODS_C" = internal global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, ptr ptrauth (ptr @"\01+[C super_test]", i32 0, i64 0, ptr getelementptr inbounds ({ i32, i32, [1 x %struct._objc_method] }, ptr @"_OBJC_$_CLASS_METHODS_C", i32 0, i32 2, i32 0, i32 2)) }] } +// CHECK: @"_OBJC_METACLASS_RO_$_C" = internal global %struct._class_ro_t { i32 129, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr @"_OBJC_$_CLASS_METHODS_C", i32 2, i64 49936, ptr getelementptr inbounds (%struct._class_ro_t, ptr @"_OBJC_METACLASS_RO_$_C", i32 0, i32 5)), ptr null, ptr null, ptr null, ptr null } +// CHECK: @"OBJC_CLASS_$_Base" = external global %struct._class_t +// CHECK: @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 128, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null } +// @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 128, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr null, i32 2, i64 49936, ptr getelementptr inbounds (%struct._class_ro_t, ptr @"_OBJC_CLASS_RO_$_C", i32 0, i32 5)), ptr null, ptr null, ptr null, ptr null } +// CHECK: @"OBJC_CLASS_$_C" = global %struct._class_t { ptr ptrauth (ptr @"OBJC_METACLASS_$_C", i32 2, i64 27361, ptr @"OBJC_CLASS_$_C"), ptr ptrauth (ptr @"OBJC_CLASS_$_Base", i32 2, i64 46507, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_CLASS_$_C", i32 0, i32 1)), ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_C" } +// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_C"] + +@interface Base ++ (void)test; +@end + +@interface C : Base +@end + +@implementation C +// CHECK-LABEL: define internal void @"\01+[C super_test]"(ptr %self, ptr %_cmd) #1 { ++ (void)super_test { + return [super test]; + // CHECK: [[SELF_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[CMD_ADDR:%.*]] = alloca ptr, align 8 + // CHECK: [[SUPER_STRUCT:%.*]] = alloca %struct._objc_super, align 8 + // CHECK: store ptr %self, ptr [[SELF_ADDR]], align 8, !tbaa !{{[0-9]+}} + // CHECK: store ptr %_cmd, ptr [[CMD_ADDR]], align 8, !tbaa !{{[0-9]+}} + // CHECK: [[TARGET:%.*]] = load ptr, ptr [[SELF_ADDR]], align 8, !tbaa !{{[0-9]+}} + // CHECK: [[OBJC_SUPER_TARGET:%.*]] = getelementptr inbounds nuw %struct._objc_super, ptr [[SUPER_STRUCT]], i32 0, i32 0 + // CHECK: store ptr [[TARGET]], ptr [[OBJC_SUPER_TARGET]], align 8 + // CHECK: [[SUPER_REFERENCES:%.*]] = load ptr, ptr @"OBJC_CLASSLIST_SUP_REFS_$_" + // CHECK: [[OBJC_SUPER_SUPER:%.*]] = getelementptr inbounds nuw %struct._objc_super, ptr [[SUPER_STRUCT]], i32 0, i32 1 + // CHECK: store ptr [[SUPER_REFERENCES]], ptr [[OBJC_SUPER_SUPER:%.*]], align 8 + // CHECK: call void @objc_msgSendSuper2(ptr %objc_super, ptr %4) +} +@end + +id str = @""; diff --git a/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m b/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m new file mode 100644 index 0000000000000..e7cb5642ee490 --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -Wno-objc-root-class -fptrauth-calls -triple arm64e -fptrauth-objc-class-ro %s -emit-llvm -o - | FileCheck %s +@interface X +@end + +@implementation X +-(void)meth {} +@end + +// CHECK: @"OBJC_CLASS_$_X" = global %struct._class_t { ptr @"OBJC_METACLASS_$_X", ptr null, ptr @_objc_empty_cache, ptr null, ptr ptrauth (ptr @"_OBJC_CLASS_RO_$_X", i32 2, i64 25080, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_CLASS_$_X", i32 0, i32 4)) } +// CHECK: @"OBJC_METACLASS_$_X" = global %struct._class_t { ptr @"OBJC_METACLASS_$_X", ptr @"OBJC_CLASS_$_X", ptr @_objc_empty_cache, ptr null, ptr ptrauth (ptr @"_OBJC_METACLASS_RO_$_X", i32 2, i64 25080, ptr getelementptr inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_X", i32 0, i32 4)) } +// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"X\00" +// CHECK: @"_OBJC_METACLASS_RO_$_X" = private global %struct._class_ro_t { i32 3, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null } +// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [5 x i8] c"meth\00" +// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"v16@0:8\00" +// CHECK: @"_OBJC_$_INSTANCE_METHODS_X" = private global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr ptrauth (ptr @"\01-[X meth]", i32 0, i64 0, ptr getelementptr inbounds ({ i32, i32, [1 x %struct._objc_method] }, ptr @"_OBJC_$_INSTANCE_METHODS_X", i32 0, i32 2, i32 0, i32 2)) }] } +// CHECK: @"_OBJC_CLASS_RO_$_X" = private global %struct._class_ro_t { i32 2, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr @"_OBJC_$_INSTANCE_METHODS_X", i32 2, i64 49936, ptr getelementptr inbounds (%struct._class_ro_t, ptr @"_OBJC_CLASS_RO_$_X", i32 0, i32 5)), ptr null, ptr null, ptr null, ptr null } +// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_X"] diff --git a/clang/test/CodeGenObjC/ptrauth-property-backing.m b/clang/test/CodeGenObjC/ptrauth-property-backing.m new file mode 100644 index 0000000000000..8c6bcb45e7446 --- /dev/null +++ b/clang/test/CodeGenObjC/ptrauth-property-backing.m @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -fexceptions -fptrauth-intrinsics -o - %s | FileCheck %s + +typedef void (*func)(); + +__attribute__((objc_root_class)) +@interface Root { + Class isa; + void *__ptrauth(1, 1, 1) _field1; + void *__ptrauth(1, 1, 1) _field2; + func __ptrauth(1, 1, 1) _field3; + func __ptrauth(1, 1, 123) _field4; +} + +@property void *field1; +@property(nonatomic) void *field2; +@property func field3; +@property(nonatomic) func field4; +@end + +@implementation Root +@end + +// CHECK-LABEL: define internal ptr @"\01-[Root field1]" +// CHECK: [[LOAD:%.*]] = load atomic i64, ptr [[ADDR:%.*]] unordered +// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 +// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 1) +// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[LOAD]], i32 1, i64 [[BLEND]]) + +// CHECK-LABEL: define internal void @"\01-[Root setField1:]" +// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR:%.*]] to i64 +// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 1) +// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[VALUE:%.*]], i32 1, i64 [[BLEND]]) +// CHECK: [[PHI:%.*]] = phi i64 [ 0, {{%.*}} ], [ [[RESULT]], {{%.*}} ] +// CHECK: store atomic i64 [[PHI]], ptr [[ADDR]] unordered + +// CHECK-LABEL: define internal ptr @"\01-[Root field2]" +// CHECK: load ptr, ptr +// CHECK: [[LOAD:%.*]] = load ptr, ptr [[ADDR:%.*]], +// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 +// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR:%.*]], i64 1) +// CHECK: [[VALUE:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLEND]]) + +// CHECK-LABEL: define internal void @"\01-[Root setField2:]" +// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR:%.*]] to i64 +// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 1) +// CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[VALUE:%.*]] to i64 +// CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CAST_VALUE]], i32 1, i64 [[BLEND]]) +// CHECK: [[RESULT:%.*]] = inttoptr i64 [[SIGNED]] to ptr +// CHECK: [[PHI:%.*]] = phi ptr [ null, {{%.*}} ], [ [[RESULT]], {{%.*}} ] +// CHECK: store ptr [[PHI]], ptr [[ADDR]] + +// CHECK-LABEL: define internal ptr @"\01-[Root field3]" +// CHECK: [[VALUE:%.*]] = load atomic i64, ptr [[ADDR:%.*]] unordered, align 8 +// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 +// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], i64 1) +// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 1, i64 [[BLENDED]], i32 0, i64 0 + +// CHECK-LABEL: define internal void @"\01-[Root setField3:]" +// CHECK: [[VALUE:%.*]] = load i64, ptr {{%.*}}, align 8 +// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr {{%.*}} to i64 +// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], i64 1) +// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 0, i64 0, i32 1, i64 [[BLENDED]]) +// CHECK: store atomic i64 + +// CHECK-LABEL: define internal ptr @"\01-[Root field4]" +// CHECK: load ptr, ptr +// CHECK: [[VALUE:%.*]] = load ptr, ptr [[ADDR:%.*]], +// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 +// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], i64 123) +// CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[VALUE]] to i64 +// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[CAST_VALUE]], i32 1, i64 [[BLENDED]], i32 0, i64 0) + +// CHECK-LABEL: define internal void @"\01-[Root setField4:]" +// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr {{%.*}} to i64 +// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 123) +// CHECK: resign.nonnull: +// CHECK: [[VALUE:%.*]] = ptrtoint ptr %1 to i64 +// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 0, i64 0, i32 1, i64 [[BLENDED]]) + diff --git a/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm b/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm new file mode 100644 index 0000000000000..fc90f5ffcbcf6 --- /dev/null +++ b/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -O0 -Wobjc-root-class -fptrauth-intrinsics -fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm -fptrauth-objc-interface-sel -o - %s | FileCheck --check-prefix=CHECK-AUTHENTICATED-SEL %s +// RUN: %clang_cc1 -O0 -Wobjc-root-class -fptrauth-intrinsics -fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNAUTHENTICATED-SEL %s + +#include <ptrauth.h> +#define __ptrauth_objc_sel_override \ + __ptrauth(ptrauth_key_objc_sel_pointer, 1, 22467) + +extern "C" { + +@interface Test { +@public + SEL auto_sel; +@public + const SEL const_auto_sel; +@public + volatile SEL volatile_auto_sel; +@public + SEL __ptrauth_objc_sel_override manual; +@public + const SEL __ptrauth_objc_sel_override const_manual; +@public + volatile SEL __ptrauth_objc_sel_override volatile_manual; +} + +@end +#if __has_feature(ptrauth_objc_interface_sel) +typedef const SEL __ptrauth_objc_sel const_auto_sel_ptr_type; +const_auto_sel_ptr_type *const_auto_sel_ptr_type_test; +typedef volatile SEL __ptrauth_objc_sel volatile_auto_sel_ptr_type; +volatile_auto_sel_ptr_type *volatile_auto_sel_ptr_type_test; +#else +typedef const SEL const_auto_sel_ptr_type; +const_auto_sel_ptr_type *const_auto_sel_ptr_type_test; +typedef volatile SEL volatile_auto_sel_ptr_type; +volatile_auto_sel_ptr_type *volatile_auto_sel_ptr_type_test; +#endif + +void auto_sel(Test *out, Test *in) { + out->auto_sel = in->auto_sel; +} +// CHECK-AUTHENTICATED-SEL: define void @auto_sel +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +// CHECK-UNAUTHENTICATED-SEL: define void @auto_sel +SEL const_auto_sel(Test *in) { + const_auto_sel_ptr_type_test = &in->const_auto_sel; + return in->const_auto_sel; +} + +// CHECK-AUTHENTICATED-SEL: define ptr @const_auto_sel +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 22466) +// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64 +// CHECK-AUTHENTICATED-SEL: [[AUTHENTICATED:%.*]] = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}}) +// CHECK-AUTHENTICATED-SEL: [[RESULT:%.*]] = inttoptr i64 [[AUTHENTICATED]] to ptr + +void volatile_auto_sel(Test *out, Test *in) { + volatile_auto_sel_ptr_type_test = &in->volatile_auto_sel; + out->volatile_auto_sel = in->volatile_auto_sel; +} + +// CHECK-AUTHENTICATED-SEL: define void @volatile_auto_sel +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +void manual(Test *out, Test *in) { + out->manual = in->manual; +} + +// CHECK-AUTHENTICATED-SEL: define void @manual +// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467) +// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467) +// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +// CHECK-UNAUTHENTICATED-SEL: define void @manual +// CHECK-UNAUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467) +// CHECK-UNAUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr [[SRC_ADDR:%.*]] to i64 +// CHECK-UNAUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467) +// CHECK-UNAUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr [[SRC_SEL_ADDR:%.*]] to i64 +// CHECK-UNAUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]]) + +} diff --git a/clang/test/SemaObjC/ptrauth-pointers.m b/clang/test/SemaObjC/ptrauth-pointers.m new file mode 100644 index 0000000000000..5a3bd49d74f0d --- /dev/null +++ b/clang/test/SemaObjC/ptrauth-pointers.m @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fblocks -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -verify %s + +#if __has_feature(ptrauth_objc_signable_class) +@class TestClass; +typedef TestClass *ClassPtr; +typedef void(^BlockPtr)(); +@interface TestClass { +@public + __ptrauth(2, 1, 1) Class a; + __ptrauth(2, 1, 3) volatile Class vi; + __ptrauth(2, 1, 3) const Class ci; + __ptrauth(2, 1, 1) id b; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'id' is invalid}} + __ptrauth(2, 1, 2) ClassPtr c; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}} + __ptrauth(2, 1, 2) BlockPtr d; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}} +} + +struct TestStruct { + __ptrauth(2, 1, 3) Class e; + __ptrauth(2, 1, 3) volatile Class vi; + __ptrauth(2, 1, 3) const Class ci; + __ptrauth(2, 1, 4) id f; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'id' is invalid}} + __ptrauth(2, 1, 5) ClassPtr g; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}} + __ptrauth(2, 1, 2) BlockPtr h; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}} +}; + +@end + +void foo() { + __ptrauth(2, 1, 3) Class i; + __ptrauth(2, 1, 3) volatile Class vi; + __ptrauth(2, 1, 3) const Class ci = 0; + __ptrauth(2, 1, 4) id j; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'id' is invalid}} + __ptrauth(2, 1, 5) ClassPtr k; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}} + __ptrauth(2, 1, 2) BlockPtr l; + // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}} +} + +#endif diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m index 98d0248f169be..74bbe6f09899b 100644 --- a/clang/test/SemaObjC/ptrauth-qualifier.m +++ b/clang/test/SemaObjC/ptrauth-qualifier.m @@ -18,12 +18,24 @@ @interface Foo @property void *__ptrauth(1, 0, 1) invalid2; // expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} +@property unsigned long long __ptrauth(1, 1, 1) invalid3; +// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is '__ptrauth(1,1,1) unsigned long long'}} + +@property unsigned long long __ptrauth(1, 0, 1) invalid4; +// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is '__ptrauth(1,0,1) unsigned long long'}} + - (void *__ptrauth(1, 1, 1))invalid5; // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} - (void *__ptrauth(1, 0, 1))invalid6; // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} +- (unsigned long long __ptrauth(1, 1, 1))invalid7; +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(1,1,1) unsigned long long'}} + +- (unsigned long long __ptrauth(1, 0, 1))invalid8; +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(1,0,1) unsigned long long'}} + - (void)invalid9:(void *__ptrauth(1, 1, 1))a; // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} // expected-note@-2 {{method 'invalid9:' declared here}} @@ -32,10 +44,17 @@ - (void)invalid10:(void *__ptrauth(1, 0, 1))a; // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} // expected-note@-2 {{method 'invalid10:' declared here}} +- (void)invalid11:(unsigned long long __ptrauth(1, 1, 1))a; +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(1,1,1) unsigned long long'}} +// expected-note@-2 {{method 'invalid11:' declared here}} + +- (void)invalid12:(unsigned long long __ptrauth(1, 0, 1))a; +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(1,0,1) unsigned long long'}} +// expected-note@-2 {{method 'invalid12:' declared here}} @end @implementation Foo -// expected-warning@-1 2{{method definition for}} +// expected-warning@-1 4{{method definition for}} - (void *__ptrauth(1, 1, 1))invalid13 { // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} @@ -47,6 +66,16 @@ @implementation Foo return 0; } +- (unsigned long long __ptrauth(1, 1, 1))invalid15 { +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(1,1,1) unsigned long long'}} + return 0; +} + +- (unsigned long long __ptrauth(1, 0, 1))invalid16 { +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(1,0,1) unsigned long long'}} + return 0; +} + - (void)invalid17:(void *__ptrauth(1, 1, 1))a { // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} } @@ -55,4 +84,12 @@ - (void)invalid18:(void *__ptrauth(1, 0, 1))a { // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} } +- (void)invalid19:(unsigned long long __ptrauth(1, 1, 1))a { +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(1,1,1) unsigned long long'}} +} + +- (void)invalid20:(unsigned long long __ptrauth(1, 0, 1))a { +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(1,0,1) unsigned long long'}} +} + @end _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits