Skip to content

Commit 9dceb37

Browse files
authored
Merge pull request #63259 from meg-gupta/ptrauthaddrdiversified1
Initial support for importing address diversified pointer auth qualified field function pointers
2 parents 8738c81 + 1dac5d4 commit 9dceb37

File tree

12 files changed

+260
-65
lines changed

12 files changed

+260
-65
lines changed

include/swift/AST/Decl.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -613,13 +613,16 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
613613
IsActor : 1
614614
);
615615

616-
SWIFT_INLINE_BITFIELD(
617-
StructDecl, NominalTypeDecl, 1 + 1,
618-
/// True if this struct has storage for fields that aren't accessible in
619-
/// Swift.
620-
HasUnreferenceableStorage : 1,
621-
/// True if this struct is imported from C++ and does not have trivial value witness functions.
622-
IsCxxNonTrivial : 1);
616+
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1 + 1 + 1,
617+
/// True if this struct has storage for fields that
618+
/// aren't accessible in Swift.
619+
HasUnreferenceableStorage : 1,
620+
/// True if this struct is imported from C++ and does
621+
/// not have trivial value witness functions.
622+
IsCxxNonTrivial : 1,
623+
/// True if this struct is imported from C and has
624+
/// address diversified ptrauth qualified field.
625+
IsNonTrivialPtrAuth : 1);
623626

624627
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1,
625628
/// True if the enum has cases and at least one case has associated values.
@@ -4267,6 +4270,14 @@ class StructDecl final : public NominalTypeDecl {
42674270

42684271
void setIsCxxNonTrivial(bool v) { Bits.StructDecl.IsCxxNonTrivial = v; }
42694272

4273+
bool isNonTrivialPtrAuth() const {
4274+
return Bits.StructDecl.IsNonTrivialPtrAuth;
4275+
}
4276+
4277+
void setHasNonTrivialPtrAuth(bool v) {
4278+
Bits.StructDecl.IsNonTrivialPtrAuth = v;
4279+
}
4280+
42704281
Type getTemplateInstantiationType() const { return TemplateInstantiationType; }
42714282
void setTemplateInstantiationType(Type t) { TemplateInstantiationType = t; }
42724283
};

lib/ClangImporter/ImportDecl.cpp

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,26 +2024,45 @@ namespace {
20242024
return nullptr;
20252025
}
20262026

2027+
auto isNonTrivialDueToAddressDiversifiedPtrAuth =
2028+
[](const clang::RecordDecl *decl) {
2029+
for (auto *field : decl->fields()) {
2030+
if (!field->getType().isNonTrivialToPrimitiveCopy()) {
2031+
continue;
2032+
}
2033+
if (field->getType().isNonTrivialToPrimitiveCopy() !=
2034+
clang::QualType::PCK_PtrAuth) {
2035+
return false;
2036+
}
2037+
}
2038+
return true;
2039+
};
2040+
2041+
bool isNonTrivialPtrAuth = false;
20272042
// FIXME: We should actually support strong ARC references and similar in
20282043
// C structs. That'll require some SIL and IRGen work, though.
20292044
if (decl->isNonTrivialToPrimitiveCopy() ||
20302045
decl->isNonTrivialToPrimitiveDestroy()) {
2031-
// Note that there is a third predicate related to these,
2032-
// isNonTrivialToPrimitiveDefaultInitialize. That one's not important
2033-
// for us because Swift never "trivially default-initializes" a struct
2034-
// (i.e. uses whatever bits were lying around as an initial value).
2035-
2036-
// FIXME: It would be nice to instead import the declaration but mark
2037-
// it as unavailable, but then it might get used as a type for an
2038-
// imported function and the developer would be able to use it without
2039-
// referencing the name, which would sidestep our availability
2040-
// diagnostics.
2041-
Impl.addImportDiagnostic(
2042-
decl, Diagnostic(
2043-
diag::record_non_trivial_copy_destroy,
2044-
Impl.SwiftContext.AllocateCopy(decl->getNameAsString())),
2045-
decl->getLocation());
2046-
return nullptr;
2046+
isNonTrivialPtrAuth = isNonTrivialDueToAddressDiversifiedPtrAuth(decl);
2047+
if (!isNonTrivialPtrAuth) {
2048+
// Note that there is a third predicate related to these,
2049+
// isNonTrivialToPrimitiveDefaultInitialize. That one's not important
2050+
// for us because Swift never "trivially default-initializes" a struct
2051+
// (i.e. uses whatever bits were lying around as an initial value).
2052+
2053+
// FIXME: It would be nice to instead import the declaration but mark
2054+
// it as unavailable, but then it might get used as a type for an
2055+
// imported function and the developer would be able to use it without
2056+
// referencing the name, which would sidestep our availability
2057+
// diagnostics.
2058+
Impl.addImportDiagnostic(
2059+
decl,
2060+
Diagnostic(
2061+
diag::record_non_trivial_copy_destroy,
2062+
Impl.SwiftContext.AllocateCopy(decl->getNameAsString())),
2063+
decl->getLocation());
2064+
return nullptr;
2065+
}
20472066
}
20482067

20492068
// Import the name.
@@ -2346,8 +2365,12 @@ namespace {
23462365
}
23472366
}
23482367

2349-
if (auto structResult = dyn_cast<StructDecl>(result))
2368+
if (auto structResult = dyn_cast<StructDecl>(result)) {
23502369
structResult->setHasUnreferenceableStorage(hasUnreferenceableStorage);
2370+
if (isNonTrivialPtrAuth) {
2371+
structResult->setHasNonTrivialPtrAuth(true);
2372+
}
2373+
}
23512374

23522375
if (cxxRecordDecl) {
23532376
if (auto structResult = dyn_cast<StructDecl>(result))

lib/IRGen/Callee.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ namespace irgen {
7878
llvm::Value *storageAddress,
7979
const PointerAuthEntity &entity);
8080

81-
static PointerAuthInfo emit(IRGenModule &IGM,
82-
clang::PointerAuthQualifier pointerAuthQual);
81+
static PointerAuthInfo emit(IRGenFunction &IGF,
82+
clang::PointerAuthQualifier pointerAuthQual,
83+
llvm::Value *storageAddress);
8384

8485
static PointerAuthInfo forFunctionPointer(IRGenModule &IGM,
8586
CanSILFunctionType fnType);

lib/IRGen/GenPointerAuth.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,30 @@ PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
239239
}
240240

241241
PointerAuthInfo
242-
PointerAuthInfo::emit(IRGenModule &IGM,
243-
clang::PointerAuthQualifier pointerAuthQual) {
244-
return PointerAuthInfo(
245-
pointerAuthQual.getKey(),
246-
llvm::ConstantInt::get(IGM.Int64Ty,
247-
pointerAuthQual.getExtraDiscriminator()));
242+
PointerAuthInfo::emit(IRGenFunction &IGF,
243+
clang::PointerAuthQualifier pointerAuthQual,
244+
llvm::Value *storageAddress) {
245+
unsigned key = pointerAuthQual.getKey();
246+
247+
// Produce the 'other' discriminator.
248+
auto otherDiscriminator = pointerAuthQual.getExtraDiscriminator();
249+
llvm::Value *discriminator =
250+
llvm::ConstantInt::get(IGF.IGM.Int64Ty, otherDiscriminator);
251+
252+
// Factor in the address.
253+
if (pointerAuthQual.isAddressDiscriminated()) {
254+
assert(storageAddress &&
255+
"no storage address for address-discriminated schema");
256+
257+
if (otherDiscriminator != 0) {
258+
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
259+
} else {
260+
discriminator =
261+
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
262+
}
263+
}
264+
265+
return PointerAuthInfo(key, discriminator);
248266
}
249267

250268
llvm::ConstantInt *

lib/IRGen/GenStruct.cpp

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,9 @@ namespace {
415415
}
416416
};
417417

418-
class AddressOnlyClangRecordTypeInfo final
419-
: public StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
420-
ClangFieldInfo> {
418+
class AddressOnlyCXXClangRecordTypeInfo final
419+
: public StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo,
420+
FixedTypeInfo, ClangFieldInfo> {
421421
const clang::RecordDecl *ClangDecl;
422422

423423
const clang::CXXConstructorDecl *findCopyConstructor() const {
@@ -490,10 +490,10 @@ namespace {
490490
}
491491

492492
public:
493-
AddressOnlyClangRecordTypeInfo(ArrayRef<ClangFieldInfo> fields,
494-
llvm::Type *storageType, Size size,
495-
Alignment align,
496-
const clang::RecordDecl *clangDecl)
493+
AddressOnlyCXXClangRecordTypeInfo(ArrayRef<ClangFieldInfo> fields,
494+
llvm::Type *storageType, Size size,
495+
Alignment align,
496+
const clang::RecordDecl *clangDecl)
497497
: StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
498498
fields, storageType, size,
499499
// We can't assume any spare bits in a C++ type
@@ -513,7 +513,7 @@ namespace {
513513
if (!destructor || destructor->isTrivial()) {
514514
// If we didn't find a destructor to call, bail out to the parent
515515
// implementation.
516-
StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
516+
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
517517
ClangFieldInfo>::destroy(IGF, address, T,
518518
isOutlined);
519519
return;
@@ -595,7 +595,7 @@ namespace {
595595
destAddr.getAddress());
596596
return;
597597
}
598-
StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
598+
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
599599
ClangFieldInfo>::initializeWithCopy(IGF, destAddr,
600600
srcAddr, T,
601601
isOutlined);
@@ -609,10 +609,9 @@ namespace {
609609
destAddr.getAddress());
610610
return;
611611
}
612-
StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
613-
ClangFieldInfo>::assignWithCopy(IGF, destAddr,
614-
srcAddr, T,
615-
isOutlined);
612+
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
613+
ClangFieldInfo>::assignWithCopy(IGF, destAddr, srcAddr,
614+
T, isOutlined);
616615
}
617616

618617
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
@@ -625,9 +624,8 @@ namespace {
625624
return;
626625
}
627626

628-
StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
629-
ClangFieldInfo>::initializeWithTake(IGF, dest,
630-
src, T,
627+
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
628+
ClangFieldInfo>::initializeWithTake(IGF, dest, src, T,
631629
isOutlined);
632630
}
633631

@@ -641,9 +639,8 @@ namespace {
641639
return;
642640
}
643641

644-
StructTypeInfoBase<AddressOnlyClangRecordTypeInfo, FixedTypeInfo,
645-
ClangFieldInfo>::assignWithTake(IGF, dest,
646-
src, T,
642+
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
643+
ClangFieldInfo>::assignWithTake(IGF, dest, src, T,
647644
isOutlined);
648645
}
649646

@@ -1045,9 +1042,11 @@ class ClangRecordLowering {
10451042
const TypeInfo *createTypeInfo(llvm::StructType *llvmType) {
10461043
llvmType->setBody(LLVMFields, /*packed*/ true);
10471044
if (SwiftType.getStructOrBoundGenericStruct()->isCxxNonTrivial()) {
1048-
return AddressOnlyClangRecordTypeInfo::create(
1045+
return AddressOnlyCXXClangRecordTypeInfo::create(
10491046
FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl);
10501047
}
1048+
// TODO: New AddressOnlyPtrAuthTypeInfo to handle address diversified field
1049+
// function ptrs in C structs.
10511050
return LoadableClangRecordTypeInfo::create(
10521051
FieldInfos, NextExplosionIndex, llvmType, TotalStride,
10531052
std::move(SpareBits), TotalAlignment, ClangDecl);
@@ -1265,8 +1264,8 @@ class ClangRecordLowering {
12651264
case StructTypeInfoKind::LoadableClangRecordTypeInfo: \
12661265
return structTI.as<LoadableClangRecordTypeInfo>().op(IGF, __VA_ARGS__); \
12671266
case StructTypeInfoKind::AddressOnlyClangRecordTypeInfo: \
1268-
return structTI.as<AddressOnlyClangRecordTypeInfo>().op(IGF, \
1269-
__VA_ARGS__); \
1267+
return structTI.as<AddressOnlyCXXClangRecordTypeInfo>().op(IGF, \
1268+
__VA_ARGS__); \
12701269
case StructTypeInfoKind::LoadableStructTypeInfo: \
12711270
return structTI.as<LoadableStructTypeInfo>().op(IGF, __VA_ARGS__); \
12721271
case StructTypeInfoKind::FixedStructTypeInfo: \

lib/IRGen/IRGenSIL.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5811,7 +5811,8 @@ void IRGenSILFunction::visitBeginAccessInst(BeginAccessInst *access) {
58115811
auto *signedFptr = Builder.CreateLoad(pointerToIntPtr, Int64PtrTy,
58125812
IGM.getPointerAlignment());
58135813
auto *resignedFptr = emitPointerAuthResign(
5814-
*this, signedFptr, PointerAuthInfo::emit(IGM, pointerAuthQual),
5814+
*this, signedFptr,
5815+
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr),
58155816
PointerAuthInfo::emit(*this,
58165817
IGM.getOptions().PointerAuth.FunctionPointers,
58175818
pointerToSignedFptr, PointerAuthEntity()));
@@ -5926,6 +5927,8 @@ void IRGenSILFunction::visitEndAccessInst(EndAccessInst *i) {
59265927
auto pointerAuthQual = cast<StructElementAddrInst>(access->getOperand())
59275928
->getField()
59285929
->getPointerAuthQualifier();
5930+
auto *pointerToSignedFptr =
5931+
getLoweredAddress(access->getOperand()).getAddress();
59295932
auto tempAddress = getLoweredAddress(access);
59305933
auto *tempAddressToIntPtr =
59315934
Builder.CreateBitCast(tempAddress.getAddress(), Int64PtrPtrTy);
@@ -5936,10 +5939,8 @@ void IRGenSILFunction::visitEndAccessInst(EndAccessInst *i) {
59365939
PointerAuthInfo::emit(*this,
59375940
IGM.getOptions().PointerAuth.FunctionPointers,
59385941
tempAddress.getAddress(), PointerAuthEntity()),
5939-
PointerAuthInfo::emit(IGM, pointerAuthQual));
5942+
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr));
59405943

5941-
auto *pointerToSignedFptr =
5942-
getLoweredAddress(access->getOperand()).getAddress();
59435944
auto *pointerToIntPtr =
59445945
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
59455946
Builder.CreateStore(signedFptr, pointerToIntPtr, IGM.getPointerAlignment());

lib/SIL/IR/TypeLowering.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,10 @@ namespace {
22712271

22722272
// Classify the type according to its stored properties.
22732273
for (auto field : D->getStoredProperties()) {
2274+
auto pointerAuthQual = field->getPointerAuthQualifier();
2275+
if (pointerAuthQual && pointerAuthQual.isAddressDiscriminated()) {
2276+
properties.setAddressOnly();
2277+
}
22742278
auto substFieldType =
22752279
field->getInterfaceType().subst(subMap)
22762280
->getCanonicalType();

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ namespace {
854854
auto Res = SGF.B.createStructElementAddr(loc, base.getValue(),
855855
Field, SubstFieldType);
856856

857-
if (!Field->getPointerAuthQualifier() ||
857+
if (!Field->getPointerAuthQualifier().isPresent() ||
858858
!SGF.getOptions().EnableImportPtrauthFieldFunctionPointers) {
859859
return ManagedValue::forLValue(Res);
860860
}

test/IRGen/Inputs/ptrauth_field_fptr_import.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@
22
#define TEST_C_FUNCTION
33

44
int returnInt() { return 111; }
5+
56
struct SecureStruct {
6-
int (*__ptrauth(2, 0, 88)(secure_func_ptr))();
7+
int (*__ptrauth(1, 0, 88)(secure_func_ptr))();
8+
};
9+
10+
struct AddressDiscriminatedSecureStruct {
11+
int (*__ptrauth(1, 1, 88)(secure_func_ptr))();
712
};
813

914
struct SecureStruct *ptr_to_secure_struct;
15+
struct AddressDiscriminatedSecureStruct
16+
*ptr_to_addr_discriminated_secure_struct;
1017
#endif

0 commit comments

Comments
 (0)