Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@

namespace clang {

/// Constant discriminator to be used with block descriptor pointers. The value
/// is ptrauth_string_discriminator("block_descriptor")
constexpr uint16_t BlockDescriptorConstantDiscriminator = 0xC0BB;

/// Constant discriminator to be used with function pointers in .init_array and
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
Expand Down Expand Up @@ -223,6 +227,18 @@ struct PointerAuthOptions {
/// The ABI for function addresses in .init_array and .fini_array
PointerAuthSchema InitFiniPointers;

/// The ABI for block invocation function pointers.
PointerAuthSchema BlockInvocationFunctionPointers;

/// The ABI for block object copy/destroy function pointers.
PointerAuthSchema BlockHelperFunctionPointers;

/// The ABI for __block variable copy/destroy function pointers.
PointerAuthSchema BlockByrefHelperFunctionPointers;

/// The ABI for pointers to block descriptors.
PointerAuthSchema BlockDescriptorPointers;

/// The ABI for Objective-C method lists.
PointerAuthSchema ObjCMethodListFunctionPointers;

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/Address.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ class Address {
static Address invalid() { return Address(nullptr); }
bool isValid() const { return Pointer.getPointer() != nullptr; }

llvm::Value *getPointerIfNotSigned() const {
assert(isValid() && "pointer isn't valid");
return !isSigned() ? Pointer.getPointer() : nullptr;
}

/// This function is used in situations where the caller is doing some sort of
/// opaque "laundering" of the pointer.
void replaceBasePointer(llvm::Value *P) {
Expand Down
99 changes: 71 additions & 28 deletions clang/lib/CodeGen/CGBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,14 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
// Optional copy/dispose helpers.
bool hasInternalHelper = false;
if (blockInfo.NeedsCopyDispose) {
auto &Schema = CGM.getCodeGenOpts().PointerAuth.BlockHelperFunctionPointers;
// copy_func_helper_decl
llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo);
elements.add(copyHelper);
elements.addSignedPointer(copyHelper, Schema, GlobalDecl(), QualType());

// destroy_func_decl
llvm::Constant *disposeHelper = buildDisposeHelper(CGM, blockInfo);
elements.add(disposeHelper);
elements.addSignedPointer(disposeHelper, Schema, GlobalDecl(), QualType());

if (cast<llvm::Function>(copyHelper->stripPointerCasts())
->hasInternalLinkage() ||
Expand Down Expand Up @@ -568,9 +569,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
info.CanBeGlobal = true;
return;
}
else if (C.getLangOpts().ObjC &&
CGM.getLangOpts().getGC() == LangOptions::NonGC)
} else if (C.getLangOpts().ObjC &&
CGM.getLangOpts().getGC() == LangOptions::NonGC)
info.HasCapturedVariableLayout = true;

if (block->doesNotEscape())
Expand Down Expand Up @@ -784,7 +784,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {

llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL;
auto GenVoidPtrTy =
llvm::PointerType *GenVoidPtrTy =
IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy;
LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default;
auto GenVoidPtrSize = CharUnits::fromQuantity(
Expand Down Expand Up @@ -818,9 +818,6 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
: CGM.getNSConcreteStackBlock();
isa = blockISA;

// Build the block descriptor.
descriptor = buildBlockDescriptor(CGM, blockInfo);

// Compute the initial on-stack block flags.
if (!CGM.getCodeGenOpts().DisableBlockSignatureString)
flags = BLOCK_HAS_SIGNATURE;
Expand All @@ -834,6 +831,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
flags |= BLOCK_USE_STRET;
if (blockInfo.NoEscape)
flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL;

// Build the block descriptor.
descriptor = buildBlockDescriptor(CGM, blockInfo);
}

auto projectField = [&](unsigned index, const Twine &name) -> Address {
Expand Down Expand Up @@ -884,19 +884,34 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()),
getIntSize(), "block.align");
}
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
if (!IsOpenCL)
addHeaderField(descriptor, getPointerSize(), "block.descriptor");
else if (auto *Helper =
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {

if (!IsOpenCL) {
llvm::Value *blockFnPtr =
llvm::ConstantExpr::getBitCast(InvokeFn, VoidPtrTy);
QualType type = blockInfo.getBlockExpr()
->getType()
->castAs<BlockPointerType>()
->getPointeeType();
addSignedHeaderField(
blockFnPtr,
CGM.getCodeGenOpts().PointerAuth.BlockInvocationFunctionPointers,
GlobalDecl(), type, getPointerSize(), "block.invoke");

addSignedHeaderField(
descriptor, CGM.getCodeGenOpts().PointerAuth.BlockDescriptorPointers,
GlobalDecl(), type, getPointerSize(), "block.descriptor");
} else if (auto *Helper =
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) {
addHeaderField(
I.first,
CharUnits::fromQuantity(
CGM.getDataLayout().getTypeAllocSize(I.first->getType())),
I.second);
}
}
} else
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
}

// Finally, capture all the values into the block.
Expand Down Expand Up @@ -1167,6 +1182,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
ASTContext &Ctx = getContext();
CallArgList Args;

llvm::Value *FuncPtr = nullptr;

if (getLangOpts().OpenCL) {
// For OpenCL, BlockPtr is already casted to generic block literal.

Expand All @@ -1186,7 +1203,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
if (!isa<ParmVarDecl>(E->getCalleeDecl()))
Func = CGM.getOpenCLRuntime().getInvokeFunction(E->getCallee());
else {
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
Func = Builder.CreateAlignedLoad(GenericVoidPtrTy, FuncPtr,
getPointerAlign());
}
Expand All @@ -1195,7 +1212,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
BlockPtr =
Builder.CreatePointerCast(BlockPtr, UnqualPtrTy, "block.literal");
// Get pointer to the block invoke function
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);

// First argument is a block literal casted to a void pointer
BlockPtr = Builder.CreatePointerCast(BlockPtr, VoidPtrTy);
Expand All @@ -1212,7 +1229,15 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy);

// Prepare the callee.
CGCallee Callee(CGCalleeInfo(), Func);
CGPointerAuthInfo PointerAuth;
if (auto &AuthSchema =
CGM.getCodeGenOpts().PointerAuth.BlockInvocationFunctionPointers) {
assert(FuncPtr != nullptr && "Missing function pointer for AuthInfo");
PointerAuth =
EmitPointerAuthInfo(AuthSchema, FuncPtr, GlobalDecl(), FnType);
}

CGCallee Callee(CGCalleeInfo(), Func, PointerAuth);

// And call the block.
return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke);
Expand Down Expand Up @@ -1296,14 +1321,15 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,

bool IsOpenCL = CGM.getLangOpts().OpenCL;
bool IsWindows = CGM.getTarget().getTriple().isOSWindows();
auto &CGOPointerAuth = CGM.getCodeGenOpts().PointerAuth;
if (!IsOpenCL) {
// isa
if (IsWindows)
fields.addNullPointer(CGM.Int8PtrPtrTy);
else
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
GlobalDecl(), QualType());
CGOPointerAuth.ObjCIsaPointers, GlobalDecl(),
QualType());

// __flags
BlockFlags flags = BLOCK_IS_GLOBAL;
Expand All @@ -1322,11 +1348,20 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
}

// Function
fields.add(blockFn);
if (auto &Schema = CGOPointerAuth.BlockInvocationFunctionPointers) {
QualType FnType = blockInfo.getBlockExpr()
->getType()
->castAs<BlockPointerType>()
->getPointeeType();
fields.addSignedPointer(blockFn, Schema, GlobalDecl(), FnType);
} else
fields.add(blockFn);

if (!IsOpenCL) {
// Descriptor
fields.add(buildBlockDescriptor(CGM, blockInfo));
llvm::Constant *Descriptor = buildBlockDescriptor(CGM, blockInfo);
fields.addSignedPointer(Descriptor, CGOPointerAuth.BlockDescriptorPointers,
GlobalDecl(), QualType());
} else if (auto *Helper =
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
for (auto *I : Helper->getCustomFieldValues(CGM, blockInfo)) {
Expand Down Expand Up @@ -1996,8 +2031,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// it. It's not quite worth the annoyance to avoid creating it in the
// first place.
if (!needsEHCleanup(captureType.isDestructedType()))
if (auto *I =
cast_or_null<llvm::Instruction>(dstField.getBasePointer()))
if (auto *I = cast_or_null<llvm::Instruction>(
dstField.getPointerIfNotSigned()))
I->eraseFromParent();
}
break;
Expand Down Expand Up @@ -2731,8 +2766,16 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
unsigned nextHeaderIndex = 0;
CharUnits nextHeaderOffset;
auto storeHeaderField = [&](llvm::Value *value, CharUnits fieldSize,
const Twine &name) {
const Twine &name, bool isFunction = false) {
auto fieldAddr = Builder.CreateStructGEP(addr, nextHeaderIndex, name);
if (isFunction) {
if (auto &Schema = CGM.getCodeGenOpts()
.PointerAuth.BlockByrefHelperFunctionPointers) {
auto PointerAuth = EmitPointerAuthInfo(
Schema, fieldAddr.emitRawPointer(*this), GlobalDecl(), QualType());
value = EmitPointerAuthSign(PointerAuth, value);
}
}
Builder.CreateStore(value, fieldAddr);

nextHeaderIndex++;
Expand Down Expand Up @@ -2815,10 +2858,10 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
storeHeaderField(V, getIntSize(), "byref.size");

if (helpers) {
storeHeaderField(helpers->CopyHelper, getPointerSize(),
"byref.copyHelper");
storeHeaderField(helpers->CopyHelper, getPointerSize(), "byref.copyHelper",
/*isFunction=*/true);
storeHeaderField(helpers->DisposeHelper, getPointerSize(),
"byref.disposeHelper");
"byref.disposeHelper", /*isFunction=*/true);
}

if (ByRefHasLifetime && HasByrefExtendedLayout) {
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
options::OPT_fno_ptrauth_objc_interface_sel);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_class_ro,
options::OPT_fno_ptrauth_objc_class_ro);

if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
handlePAuthABI(Args, CmdArgs);

Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,16 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
Discrimination::Constant, InitFiniPointerConstantDiscriminator);
}

Opts.BlockInvocationFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
Opts.BlockHelperFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
Opts.BlockByrefHelperFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
Opts.BlockDescriptorPointers =
PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
BlockDescriptorConstantDiscriminator);

Opts.ObjCMethodListFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
Opts.ObjCMethodListPointer =
Expand Down Expand Up @@ -3621,7 +3631,6 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Opts.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got);
Opts.AArch64JumpTableHardening =
Args.hasArg(OPT_faarch64_jump_table_hardening);

Opts.PointerAuthObjcIsa = Args.hasArg(OPT_fptrauth_objc_isa);
Opts.PointerAuthObjcClassROPointers = Args.hasArg(OPT_fptrauth_objc_class_ro);
Opts.PointerAuthObjcInterfaceSel =
Expand Down
10 changes: 8 additions & 2 deletions clang/test/CodeGen/ptrauth-qualifier-blocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,15 @@ void test_block_address_byref_capture() {
// CHECK: store i32 33554432,
// CHECK: store i32 48,
// CHECK: [[COPY_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 4
// CHECK: store ptr @__Block_byref_object_copy_, ptr [[COPY_HELPER_FIELD]], align
// CHECK: [[T0:%.*]] = ptrtoint ptr [[COPY_HELPER_FIELD]] to i64
// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_copy_ to i64), i32 0, i64 [[T0]])
// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK: store ptr [[T2]], ptr [[COPY_HELPER_FIELD]], align
// CHECK: [[DISPOSE_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 5
// CHECK: store ptr @__Block_byref_object_dispose_, ptr [[DISPOSE_HELPER_FIELD]], align
// CHECK: [[T0:%.*]] = ptrtoint ptr [[DISPOSE_HELPER_FIELD]] to i64
// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_dispose_ to i64), i32 0, i64 [[T0]])
// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK: store ptr [[T2]], ptr [[DISPOSE_HELPER_FIELD]], align
// flags - copy/dispose required
// CHECK: store i32 1107296256, ptr
__block struct A * __ptrauth(1, 1, 60) ptr = createA();
Expand Down
28 changes: 28 additions & 0 deletions clang/test/CodeGenObjC/ptrauth-block-descriptor-pointer.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %clang_cc1 -fobjc-arc -fblocks -fptrauth-calls -triple arm64e-apple-ios -emit-llvm -o - %s | FileCheck %s

_Static_assert(__has_feature(ptrauth_signed_block_descriptors), "-fptrauth-block-descriptor-pointers should set ptrauth_signed_block_descriptors");

void a() {
// Test out a global block.
void (^blk)(void) = ^{};
}

// CHECK: [[BLOCK_DESCRIPTOR_NAME:@"__block_descriptor_.*"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 32, ptr @.str, ptr null }


// CHECK: @__block_literal_global = internal constant { ptr, i32, i32, ptr, ptr } { ptr @_NSConcreteGlobalBlock, i32 1342177280, i32 0, ptr ptrauth (ptr @__a_block_invoke, i32 0, i64 0, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 3)), ptr ptrauth (ptr @"__block_descriptor_32_e5_v8\01?0l", i32 2, i64 49339, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 4)) }

void b(int p) {
// CHECK-LABEL: define void @b

// Test out a stack block.
void (^blk)(void) = ^{(void)p;};

// CHECK: [[BLOCK:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, i32 }>
// CHECK: [[BLOCK_DESCRIPTOR_REF:%.*]] = getelementptr inbounds nuw <{ {{.*}} }>, ptr [[BLOCK]], i32 0, i32 4
// CHECK: [[BLOCK_DESCRIPTOR_REF_INT:%.*]] = ptrtoint ptr [[BLOCK_DESCRIPTOR_REF]] to i64
// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[BLOCK_DESCRIPTOR_REF_INT]], i64 49339)
// CHECK: [[SIGNED_REF:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @"__block_descriptor_36_e5_v8\01?0l" to i64), i32 2, i64 [[BLENDED]])
// CHECK: [[SIGNED_REF_PTR:%.*]] = inttoptr i64 [[SIGNED_REF]] to ptr
// CHECK: store ptr [[SIGNED_REF_PTR]], ptr [[BLOCK_DESCRIPTOR_REF]]
}
5 changes: 3 additions & 2 deletions clang/test/CodeGenObjC/ptrauth-block-isa.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -fptrauth-calls -fptrauth-objc-isa -fobjc-arc -fblocks -triple arm64e -emit-llvm %s -o - | FileCheck %s
// 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
// CHECK: [[BLOCK_DESCRIPTOR_NAME:@"__block_descriptor_.*"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 32, ptr @.str, ptr null }, comdat, align 8
// CHECK: @__block_literal_global = internal constant { ptr, i32, i32, ptr, ptr } { ptr ptrauth (ptr @_NSConcreteGlobalBlock, i32 2, i64 27361, ptr @__block_literal_global), i32 1342177280, i32 0, ptr ptrauth (ptr @globalblock_block_invoke, i32 0, i64 0, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 3)), ptr ptrauth (ptr [[BLOCK_DESCRIPTOR_NAME]], i32 2, i64 49339, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 4)) }

@interface A
- (int) count;
Expand Down