[clang][ObjC][PAC] Add ptrauth protections to objective-c (#147899)
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
This commit is contained in:
parent
90ef114a33
commit
451a9ce9ff
@ -1022,7 +1022,9 @@ Arm and AArch64 Support
|
|||||||
`as specified here <https://github.com/ARM-software/acle/blob/main/main/acle.md#modal-8-bit-floating-point-extensions>`_
|
`as specified here <https://github.com/ARM-software/acle/blob/main/main/acle.md#modal-8-bit-floating-point-extensions>`_
|
||||||
is now available.
|
is now available.
|
||||||
- Support has been added for the following processors (command-line identifiers in parentheses):
|
- Support has been added for the following processors (command-line identifiers in parentheses):
|
||||||
|
|
||||||
- Arm Cortex-A320 (``cortex-a320``)
|
- Arm Cortex-A320 (``cortex-a320``)
|
||||||
|
|
||||||
- For ARM targets, cc1as now considers the FPU's features for the selected CPU or Architecture.
|
- For ARM targets, cc1as now considers the FPU's features for the selected CPU or Architecture.
|
||||||
- The ``+nosimd`` attribute is now fully supported for ARM. Previously, this had no effect when being used with
|
- The ``+nosimd`` attribute is now fully supported for ARM. Previously, this had no effect when being used with
|
||||||
ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is
|
ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is
|
||||||
@ -1030,7 +1032,19 @@ Arm and AArch64 Support
|
|||||||
- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled.
|
- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled.
|
||||||
- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled.
|
- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled.
|
||||||
|
|
||||||
|
- Pointer authentication
|
||||||
|
|
||||||
- Support for __ptrauth type qualifier has been added.
|
- Support for __ptrauth type qualifier has been added.
|
||||||
|
- Objective-C adoption of pointer authentication
|
||||||
|
|
||||||
|
- ``isa`` and ``super`` pointers are protected with address diversity and separate
|
||||||
|
usage specific discriminators.
|
||||||
|
- methodlist pointers and content are protected with address diversity and methodlist
|
||||||
|
pointers have a usage specific discriminator.
|
||||||
|
- ``class_ro_t`` pointers are protected with address diversity and usage specific
|
||||||
|
discriminators.
|
||||||
|
- ``SEL`` typed ivars are protected with address diversity and usage specific
|
||||||
|
discriminators.
|
||||||
|
|
||||||
- For AArch64, added support for generating executable-only code sections by using the
|
- For AArch64, added support for generating executable-only code sections by using the
|
||||||
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)
|
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)
|
||||||
|
@ -2300,6 +2300,8 @@ public:
|
|||||||
return getTypeDeclType(getObjCSelDecl());
|
return getTypeDeclType(getObjCSelDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerAuthQualifier getObjCMemberSelTypePtrAuth();
|
||||||
|
|
||||||
/// Retrieve the typedef declaration corresponding to the predefined
|
/// Retrieve the typedef declaration corresponding to the predefined
|
||||||
/// Objective-C 'Class' type.
|
/// Objective-C 'Class' type.
|
||||||
TypedefDecl *getObjCClassDecl() const;
|
TypedefDecl *getObjCClassDecl() const;
|
||||||
|
@ -160,6 +160,12 @@ FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
|
|||||||
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
|
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
|
||||||
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
|
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
|
||||||
FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
|
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,
|
EXTENSION(swiftcc,
|
||||||
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
|
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
|
||||||
clang::TargetInfo::CCCR_OK)
|
clang::TargetInfo::CCCR_OK)
|
||||||
|
@ -133,6 +133,11 @@ LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, NotCompatible,
|
|||||||
LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from GOT")
|
LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from GOT")
|
||||||
LANGOPT(AArch64JumpTableHardening, 1, 0, NotCompatible, "use hardened lowering for jump-table dispatch")
|
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(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes")
|
||||||
LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes")
|
LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes")
|
||||||
|
|
||||||
|
@ -27,6 +27,26 @@ namespace clang {
|
|||||||
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
|
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
|
||||||
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
|
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;
|
constexpr unsigned PointerAuthKeyNone = -1;
|
||||||
|
|
||||||
/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
|
/// 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
|
/// The ABI for function addresses in .init_array and .fini_array
|
||||||
PointerAuthSchema InitFiniPointers;
|
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
|
} // end namespace clang
|
||||||
|
@ -4504,6 +4504,9 @@ defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini
|
|||||||
"Enable address discrimination of function pointers in init/fini arrays">;
|
"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 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 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>,
|
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
|
||||||
|
@ -9783,6 +9783,17 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
|
|||||||
return ObjCProtocolClassDecl;
|
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
|
// __builtin_va_list Construction Functions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -853,9 +853,24 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
|||||||
offset += size;
|
offset += size;
|
||||||
index++;
|
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) {
|
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()),
|
addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
|
||||||
getIntSize(), "block.flags");
|
getIntSize(), "block.flags");
|
||||||
addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
|
addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
|
||||||
@ -1285,7 +1300,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
|
|||||||
if (IsWindows)
|
if (IsWindows)
|
||||||
fields.addNullPointer(CGM.Int8PtrPtrTy);
|
fields.addNullPointer(CGM.Int8PtrPtrTy);
|
||||||
else
|
else
|
||||||
fields.add(CGM.getNSConcreteGlobalBlock());
|
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
|
||||||
|
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
|
||||||
|
GlobalDecl(), QualType());
|
||||||
|
|
||||||
// __flags
|
// __flags
|
||||||
BlockFlags flags = BLOCK_IS_GLOBAL;
|
BlockFlags flags = BLOCK_IS_GLOBAL;
|
||||||
|
@ -1193,16 +1193,23 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||||||
ivarAddr = ivarAddr.withElementType(bitcastType);
|
ivarAddr = ivarAddr.withElementType(bitcastType);
|
||||||
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
|
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
|
||||||
load->setAtomic(llvm::AtomicOrdering::Unordered);
|
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
|
// Store that value into the return address. Doing this with a
|
||||||
// bitcast is likely to produce some pretty ugly IR, but it's not
|
// bitcast is likely to produce some pretty ugly IR, but it's not
|
||||||
// the *most* terrible thing in the world.
|
// the *most* terrible thing in the world.
|
||||||
llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
|
llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
|
||||||
uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
|
uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
|
||||||
llvm::Value *ivarVal = load;
|
|
||||||
if (ivarSize > retTySize) {
|
if (ivarSize > retTySize) {
|
||||||
bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
|
bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
|
||||||
ivarVal = Builder.CreateTrunc(load, bitcastType);
|
ivarVal = Builder.CreateTrunc(ivarVal, bitcastType);
|
||||||
}
|
}
|
||||||
Builder.CreateStore(ivarVal, ReturnValue.withElementType(bitcastType));
|
Builder.CreateStore(ivarVal, ReturnValue.withElementType(bitcastType));
|
||||||
|
|
||||||
@ -1214,6 +1221,16 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||||||
case PropertyImplStrategy::GetSetProperty: {
|
case PropertyImplStrategy::GetSetProperty: {
|
||||||
llvm::FunctionCallee getPropertyFn =
|
llvm::FunctionCallee getPropertyFn =
|
||||||
CGM.getObjCRuntime().GetPropertyGetFunction();
|
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) {
|
if (!getPropertyFn) {
|
||||||
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
|
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
|
||||||
return;
|
return;
|
||||||
@ -1269,7 +1286,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||||||
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
|
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
|
||||||
|
|
||||||
QualType ivarType = ivar->getType();
|
QualType ivarType = ivar->getType();
|
||||||
switch (getEvaluationKind(ivarType)) {
|
auto EvaluationKind = getEvaluationKind(ivarType);
|
||||||
|
assert(!ivarType.getPointerAuth() || EvaluationKind == TEK_Scalar);
|
||||||
|
switch (EvaluationKind) {
|
||||||
case TEK_Complex: {
|
case TEK_Complex: {
|
||||||
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
|
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
|
||||||
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
|
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
|
||||||
@ -1287,6 +1306,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||||||
case TEK_Scalar: {
|
case TEK_Scalar: {
|
||||||
llvm::Value *value;
|
llvm::Value *value;
|
||||||
if (propType->isReferenceType()) {
|
if (propType->isReferenceType()) {
|
||||||
|
if (ivarType.getPointerAuth()) {
|
||||||
|
CGM.ErrorUnsupported(propImpl,
|
||||||
|
"Obj-C getter for authenticated reference type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
value = LV.getAddress().emitRawPointer(*this);
|
value = LV.getAddress().emitRawPointer(*this);
|
||||||
} else {
|
} else {
|
||||||
// We want to load and autoreleaseReturnValue ARC __weak ivars.
|
// 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
|
// Otherwise we want to do a simple load, suppressing the
|
||||||
// final autorelease.
|
// final autorelease.
|
||||||
} else {
|
} else {
|
||||||
|
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();
|
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
|
||||||
|
|
||||||
AutoreleaseResult = false;
|
AutoreleaseResult = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1490,6 +1526,14 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
|
|||||||
|
|
||||||
llvm::Value *load = Builder.CreateLoad(argAddr);
|
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.
|
// Perform an atomic store. There are no memory ordering requirements.
|
||||||
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
|
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
|
||||||
store->setAtomic(llvm::AtomicOrdering::Unordered);
|
store->setAtomic(llvm::AtomicOrdering::Unordered);
|
||||||
|
@ -1935,7 +1935,9 @@ CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) {
|
|||||||
auto Fields = Builder.beginStruct(NSConstantStringType);
|
auto Fields = Builder.beginStruct(NSConstantStringType);
|
||||||
|
|
||||||
// Class pointer.
|
// Class pointer.
|
||||||
Fields.add(Class);
|
Fields.addSignedPointer(Class,
|
||||||
|
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
|
||||||
|
GlobalDecl(), QualType());
|
||||||
|
|
||||||
// String pointer.
|
// String pointer.
|
||||||
llvm::Constant *C =
|
llvm::Constant *C =
|
||||||
@ -4975,10 +4977,7 @@ enum ImageInfoFlags {
|
|||||||
eImageInfo_GCOnly = (1 << 2),
|
eImageInfo_GCOnly = (1 << 2),
|
||||||
eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache.
|
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
|
eImageInfo_SignedClassRO = (1 << 4), // Reused (was _CorrectedSynthesize)
|
||||||
// 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_ImageIsSimulated = (1 << 5),
|
eImageInfo_ImageIsSimulated = (1 << 5),
|
||||||
eImageInfo_ClassProperties = (1 << 6)
|
eImageInfo_ClassProperties = (1 << 6)
|
||||||
};
|
};
|
||||||
@ -5036,6 +5035,17 @@ void CGObjCCommonMac::EmitImageInfo() {
|
|||||||
// Indicate whether we are generating class properties.
|
// Indicate whether we are generating class properties.
|
||||||
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
|
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
|
||||||
eImageInfo_ClassProperties);
|
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 {
|
// struct objc_module {
|
||||||
@ -6223,11 +6233,19 @@ llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassRoTInitializer(
|
|||||||
methods.push_back(MD);
|
methods.push_back(MD);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
|
llvm::Constant *MethListPtr = emitMethodList(
|
||||||
(flags & NonFragileABI_Class_Meta)
|
ID->getObjCRuntimeNameAsString(),
|
||||||
? MethodListType::ClassMethods
|
(flags & NonFragileABI_Class_Meta) ? MethodListType::ClassMethods
|
||||||
: MethodListType::InstanceMethods,
|
: MethodListType::InstanceMethods,
|
||||||
methods));
|
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();
|
const ObjCInterfaceDecl *OID = ID->getClassInterface();
|
||||||
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
|
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
|
||||||
@ -6275,15 +6293,20 @@ llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassObject(
|
|||||||
bool HiddenVisibility) {
|
bool HiddenVisibility) {
|
||||||
ConstantInitBuilder builder(CGM);
|
ConstantInitBuilder builder(CGM);
|
||||||
auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
|
auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
|
||||||
values.add(IsAGV);
|
const PointerAuthOptions &PointerAuthOpts = CGM.getCodeGenOpts().PointerAuth;
|
||||||
if (SuperClassGV) {
|
values.addSignedPointer(IsAGV, PointerAuthOpts.ObjCIsaPointers, GlobalDecl(),
|
||||||
values.add(SuperClassGV);
|
QualType());
|
||||||
} else {
|
if (SuperClassGV)
|
||||||
|
values.addSignedPointer(SuperClassGV, PointerAuthOpts.ObjCSuperPointers,
|
||||||
|
GlobalDecl(), QualType());
|
||||||
|
else
|
||||||
values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
|
values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
|
||||||
}
|
|
||||||
values.add(ObjCEmptyCacheVar);
|
values.add(ObjCEmptyCacheVar);
|
||||||
values.add(ObjCEmptyVtableVar);
|
values.add(ObjCEmptyVtableVar);
|
||||||
values.add(ClassRoGV);
|
|
||||||
|
values.addSignedPointer(ClassRoGV, PointerAuthOpts.ObjCClassROPointers,
|
||||||
|
GlobalDecl(), QualType());
|
||||||
|
|
||||||
llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
|
llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
|
||||||
GetClassGlobal(CI, isMetaclass, ForDefinition));
|
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);
|
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);
|
listName, MethodListType::CategoryClassMethods, classMethods);
|
||||||
values.add(instanceMethodList);
|
if (!ClassMethodList->isNullValue())
|
||||||
values.add(classMethodList);
|
values.addSignedPointer(ClassMethodList, MethListSchema, GlobalDecl(),
|
||||||
|
QualType());
|
||||||
|
else
|
||||||
|
values.add(ClassMethodList);
|
||||||
|
|
||||||
// Keep track of whether we have actual metadata to emit.
|
// Keep track of whether we have actual metadata to emit.
|
||||||
bool isEmptyCategory =
|
bool isEmptyCategory =
|
||||||
instanceMethodList->isNullValue() && classMethodList->isNullValue();
|
InstanceMethodList->isNullValue() && ClassMethodList->isNullValue();
|
||||||
|
|
||||||
const ObjCCategoryDecl *Category =
|
const ObjCCategoryDecl *Category =
|
||||||
Interface->FindCategoryDeclaration(OCD->getIdentifier());
|
Interface->FindCategoryDeclaration(OCD->getIdentifier());
|
||||||
@ -6629,6 +6664,12 @@ void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
|
|||||||
} else {
|
} else {
|
||||||
llvm::Function *fn = GetMethodDefinition(MD);
|
llvm::Function *fn = GetMethodDefinition(MD);
|
||||||
assert(fn && "no definition for method?");
|
assert(fn && "no definition for method?");
|
||||||
|
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.add(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7672,10 +7713,15 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
|
llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
|
||||||
|
llvm::Constant *VTablePtr = llvm::ConstantExpr::getInBoundsGetElementPtr(
|
||||||
|
VTableGV->getValueType(), VTableGV, VTableIdx);
|
||||||
|
|
||||||
ConstantInitBuilder builder(CGM);
|
ConstantInitBuilder builder(CGM);
|
||||||
auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
|
auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
|
||||||
values.add(llvm::ConstantExpr::getInBoundsGetElementPtr(
|
const PointerAuthSchema &TypeInfoSchema =
|
||||||
VTableGV->getValueType(), VTableGV, VTableIdx));
|
CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer;
|
||||||
|
values.addSignedPointer(VTablePtr, TypeInfoSchema, GlobalDecl(), QualType());
|
||||||
|
|
||||||
values.add(GetClassName(ClassName));
|
values.add(GetClassName(ClassName));
|
||||||
values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
|
values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
|
||||||
|
|
||||||
|
@ -6616,7 +6616,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
|
|||||||
auto Fields = Builder.beginStruct(STy);
|
auto Fields = Builder.beginStruct(STy);
|
||||||
|
|
||||||
// Class pointer.
|
// Class pointer.
|
||||||
Fields.add(cast<llvm::Constant>(CFConstantStringClassRef));
|
Fields.addSignedPointer(cast<llvm::Constant>(CFConstantStringClassRef),
|
||||||
|
getCodeGenOpts().PointerAuth.ObjCIsaPointers,
|
||||||
|
GlobalDecl(), QualType());
|
||||||
|
|
||||||
// Flags.
|
// Flags.
|
||||||
if (IsSwiftABI) {
|
if (IsSwiftABI) {
|
||||||
|
@ -1746,6 +1746,13 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
|
|||||||
Args.addOptInFlag(CmdArgs, options::OPT_faarch64_jump_table_hardening,
|
Args.addOptInFlag(CmdArgs, options::OPT_faarch64_jump_table_hardening,
|
||||||
options::OPT_fno_aarch64_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)
|
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
|
||||||
handlePAuthABI(Args, CmdArgs);
|
handlePAuthABI(Args, CmdArgs);
|
||||||
|
|
||||||
|
@ -1541,6 +1541,25 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
|
|||||||
Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination,
|
Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination,
|
||||||
Discrimination::Constant, InitFiniPointerConstantDiscriminator);
|
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.ReturnAddresses = LangOpts.PointerAuthReturns;
|
||||||
Opts.AuthTraps = LangOpts.PointerAuthAuthTraps;
|
Opts.AuthTraps = LangOpts.PointerAuthAuthTraps;
|
||||||
@ -3573,6 +3592,12 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
|
|||||||
GenerateArg(Consumer, OPT_fptrauth_elf_got);
|
GenerateArg(Consumer, OPT_fptrauth_elf_got);
|
||||||
if (Opts.AArch64JumpTableHardening)
|
if (Opts.AArch64JumpTableHardening)
|
||||||
GenerateArg(Consumer, OPT_faarch64_jump_table_hardening);
|
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,
|
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.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got);
|
||||||
Opts.AArch64JumpTableHardening =
|
Opts.AArch64JumpTableHardening =
|
||||||
Args.hasArg(OPT_faarch64_jump_table_hardening);
|
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.
|
/// Check if input file kind and language standard are compatible.
|
||||||
|
@ -42,6 +42,19 @@ typedef enum {
|
|||||||
The extra data is always 0. */
|
The extra data is always 0. */
|
||||||
ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data,
|
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. */
|
/* The key used to sign pointers in ELF .init_array/.fini_array. */
|
||||||
ptrauth_key_init_fini_pointer = ptrauth_key_process_independent_code,
|
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") */
|
/* The value is ptrauth_string_discriminator("init_fini") */
|
||||||
#define __ptrauth_init_fini_discriminator 0xd9d4
|
#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
|
#else
|
||||||
|
|
||||||
#define ptrauth_strip(__value, __key) \
|
#define ptrauth_strip(__value, __key) \
|
||||||
@ -331,6 +384,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
|
|||||||
#define ptrauth_cxx_vtable_pointer(key, address_discrimination, \
|
#define ptrauth_cxx_vtable_pointer(key, address_discrimination, \
|
||||||
extra_discrimination...)
|
extra_discrimination...)
|
||||||
|
|
||||||
|
#define __ptrauth_objc_isa_pointer
|
||||||
|
#define __ptrauth_objc_isa_uintptr
|
||||||
|
#define __ptrauth_objc_super_pointer
|
||||||
|
|
||||||
#endif /* __has_feature(ptrauth_intrinsics) */
|
#endif /* __has_feature(ptrauth_intrinsics) */
|
||||||
|
|
||||||
#endif /* __PTRAUTH_H */
|
#endif /* __PTRAUTH_H */
|
||||||
|
@ -5585,6 +5585,14 @@ Decl *SemaObjC::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D,
|
|||||||
|
|
||||||
TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
|
TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
|
||||||
QualType T = TInfo->getType();
|
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) {
|
if (BitWidth) {
|
||||||
// 6.7.2.1p3, 6.7.2.1p4
|
// 6.7.2.1p3, 6.7.2.1p4
|
||||||
|
@ -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,
|
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
|
||||||
PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
|
PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
|
||||||
PropertyIvarType, /*TInfo=*/nullptr,
|
PropertyIvarType, /*TInfo=*/nullptr,
|
||||||
|
@ -1371,13 +1371,13 @@ void test71(void) {
|
|||||||
// CHECK: %[[T:.*]] = alloca [2 x ptr], align 16
|
// CHECK: %[[T:.*]] = alloca [2 x ptr], align 16
|
||||||
// CHECK: %[[V0:.*]] = call ptr @llvm.objc.retain(ptr %[[A]])
|
// CHECK: %[[V0:.*]] = call ptr @llvm.objc.retain(ptr %[[A]])
|
||||||
// CHECK: %[[V1:.*]] = call ptr @llvm.objc.retain(ptr %[[B]]) #2
|
// 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: %[[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: %[[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: %[[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: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x ptr], ptr %[[T]], i32 0, i32 0
|
||||||
// CHECK: %[[V7:.*]] = getelementptr inbounds ptr, ptr %[[ARRAY_BEGIN]], i64 2
|
// CHECK: %[[V7:.*]] = getelementptr inbounds ptr, ptr %[[ARRAY_BEGIN]], i64 2
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ typedef double double4x4 __attribute__((matrix_type(4, 4)));
|
|||||||
// CHECK-LABEL: @test_index_placeholders(
|
// CHECK-LABEL: @test_index_placeholders(
|
||||||
// CHECK-NEXT: entry:
|
// CHECK-NEXT: entry:
|
||||||
// CHECK: [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8
|
// 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: [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], ptr noundef [[SEL]])
|
||||||
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
|
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
|
||||||
// CHECK-NEXT: [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8
|
// 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: [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], ptr noundef [[SEL2]])
|
||||||
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
|
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
|
||||||
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
|
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
|
||||||
@ -38,17 +38,17 @@ __attribute__((objc_root_class))
|
|||||||
|
|
||||||
// CHECK-LABEL: @test_base_and_index_placeholders(
|
// CHECK-LABEL: @test_base_and_index_placeholders(
|
||||||
// CHECK: [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8
|
// 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: [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], ptr noundef [[SEL]])
|
||||||
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
|
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
|
||||||
// CHECK-NEXT: [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8
|
// 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: [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], ptr noundef [[SEL2]])
|
||||||
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
|
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
|
||||||
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
|
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
|
||||||
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]]
|
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]]
|
||||||
// CHECK-NEXT: [[M:%.*]] = load ptr, ptr %m.addr, align 8
|
// 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: [[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: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]]
|
||||||
// CHECK-NEXT: ret double [[MATEXT]]
|
// CHECK-NEXT: ret double [[MATEXT]]
|
||||||
|
17
clang/test/CodeGenObjC/ptrauth-attr-exception.m
Normal file
17
clang/test/CodeGenObjC/ptrauth-attr-exception.m
Normal file
@ -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" }
|
40
clang/test/CodeGenObjC/ptrauth-block-isa.m
Normal file
40
clang/test/CodeGenObjC/ptrauth-block-isa.m
Normal file
@ -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;
|
||||||
|
});
|
||||||
|
}
|
24
clang/test/CodeGenObjC/ptrauth-class-ro.m
Normal file
24
clang/test/CodeGenObjC/ptrauth-class-ro.m
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// RUN: %clang_cc1 -triple arm64-apple-ios -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];
|
||||||
|
}
|
103
clang/test/CodeGenObjC/ptrauth-class.m
Normal file
103
clang/test/CodeGenObjC/ptrauth-class.m
Normal file
@ -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
|
130
clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m
Normal file
130
clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// RUN: %clang_cc1 -O0 -Wno-objc-root-class -fptrauth-intrinsics -fptrauth-calls -nostdsysteminc -triple arm64-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 arm64-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]])
|
57
clang/test/CodeGenObjC/ptrauth-objc-isa-super.m
Normal file
57
clang/test/CodeGenObjC/ptrauth-objc-isa-super.m
Normal file
@ -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 = @"";
|
17
clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m
Normal file
17
clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m
Normal file
@ -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"]
|
80
clang/test/CodeGenObjC/ptrauth-property-backing.m
Normal file
80
clang/test/CodeGenObjC/ptrauth-property-backing.m
Normal file
@ -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]])
|
||||||
|
|
90
clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm
Normal file
90
clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm
Normal file
@ -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]])
|
||||||
|
|
||||||
|
}
|
46
clang/test/SemaObjC/ptrauth-pointers.m
Normal file
46
clang/test/SemaObjC/ptrauth-pointers.m
Normal file
@ -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
|
@ -18,12 +18,24 @@
|
|||||||
@property void *__ptrauth(1, 0, 1) invalid2;
|
@property void *__ptrauth(1, 0, 1) invalid2;
|
||||||
// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}}
|
// 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;
|
- (void *__ptrauth(1, 1, 1))invalid5;
|
||||||
// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
||||||
|
|
||||||
- (void *__ptrauth(1, 0, 1))invalid6;
|
- (void *__ptrauth(1, 0, 1))invalid6;
|
||||||
// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}}
|
// 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;
|
- (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-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
||||||
// expected-note@-2 {{method 'invalid9:' declared here}}
|
// expected-note@-2 {{method 'invalid9:' declared here}}
|
||||||
@ -32,10 +44,17 @@
|
|||||||
// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}}
|
// 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}}
|
// 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
|
@end
|
||||||
|
|
||||||
@implementation Foo
|
@implementation Foo
|
||||||
// expected-warning@-1 2{{method definition for}}
|
// expected-warning@-1 4{{method definition for}}
|
||||||
|
|
||||||
- (void *__ptrauth(1, 1, 1))invalid13 {
|
- (void *__ptrauth(1, 1, 1))invalid13 {
|
||||||
// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
||||||
@ -47,6 +66,16 @@
|
|||||||
return 0;
|
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 {
|
- (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)'}}
|
// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}}
|
||||||
}
|
}
|
||||||
@ -55,4 +84,12 @@
|
|||||||
// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}}
|
// 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
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user