Skip to content

Commit 2092eb8

Browse files
ojhuntIanWood1
authored andcommitted
[clang] Ensure correct copying of records with authenticated fields (llvm#136783)
When records contain fields with pointer authentication, even simple copies can require additional work be performed. This patch contains the core functionality required to handle user defined structs, as well as the implicitly constructed structs for blocks, etc. Co-authored-by: Ahmed Bougacha Co-authored-by: Akira Hatanaka Co-authored-by: John Mccall
1 parent 8856c6c commit 2092eb8

14 files changed

+471
-3
lines changed

clang/include/clang/AST/NonTrivialTypeVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ struct CopiedTypeVisitor {
9393
return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
9494
case QualType::PCK_ARCWeak:
9595
return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
96+
case QualType::PCK_PtrAuth:
97+
return asDerived().visitPtrAuth(FT, std::forward<Ts>(Args)...);
9698
case QualType::PCK_Struct:
9799
return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
98100
case QualType::PCK_Trivial:

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,9 @@ class QualType {
15071507
/// with the ARC __weak qualifier.
15081508
PCK_ARCWeak,
15091509

1510+
/// The type is an address-discriminated signed pointer type.
1511+
PCK_PtrAuth,
1512+
15101513
/// The type is a struct containing a field whose type is neither
15111514
/// PCK_Trivial nor PCK_VolatileTrivial.
15121515
/// Note that a C++ struct type does not necessarily match this; C++ copying

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8372,6 +8372,9 @@ bool ASTContext::BlockRequiresCopying(QualType Ty,
83728372
return true;
83738373
}
83748374

8375+
if (Ty.hasAddressDiscriminatedPointerAuth())
8376+
return true;
8377+
83758378
// The block needs copy/destroy helpers if Ty is non-trivial to destructively
83768379
// move or destroy.
83778380
if (Ty.isNonTrivialToPrimitiveDestructiveMove() || Ty.isDestructedType())

clang/lib/AST/Type.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2817,6 +2817,9 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type,
28172817
if (CanonicalType->isIncompleteType())
28182818
return false;
28192819

2820+
if (CanonicalType.hasAddressDiscriminatedPointerAuth())
2821+
return false;
2822+
28202823
// As an extension, Clang treats vector types as Scalar types.
28212824
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
28222825
return true;
@@ -2829,7 +2832,7 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type,
28292832
return ClassDecl->isTriviallyCopyable();
28302833
}
28312834
}
2832-
return true;
2835+
return !RT->getDecl()->isNonTrivialToPrimitiveCopy();
28332836
}
28342837
// No other types can match.
28352838
return false;
@@ -2967,6 +2970,8 @@ QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const {
29672970
case Qualifiers::OCL_Weak:
29682971
return PCK_ARCWeak;
29692972
default:
2973+
if (hasAddressDiscriminatedPointerAuth())
2974+
return PCK_PtrAuth;
29702975
return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial;
29712976
}
29722977
}

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
15911591
return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
15921592
}
15931593

1594+
if (T.hasAddressDiscriminatedPointerAuth())
1595+
return std::make_pair(
1596+
BlockCaptureEntityKind::AddressDiscriminatedPointerAuth, Flags);
1597+
15941598
Flags = BLOCK_FIELD_IS_OBJECT;
15951599
bool isBlockPointer = T->isBlockPointerType();
15961600
if (isBlockPointer)
@@ -1611,6 +1615,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
16111615
return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong
16121616
: BlockCaptureEntityKind::BlockObject,
16131617
Flags);
1618+
case QualType::PCK_PtrAuth:
1619+
return std::make_pair(
1620+
BlockCaptureEntityKind::AddressDiscriminatedPointerAuth,
1621+
BlockFieldFlags());
16141622
case QualType::PCK_Trivial:
16151623
case QualType::PCK_VolatileTrivial: {
16161624
if (!T->isObjCRetainableType())
@@ -1713,6 +1721,13 @@ static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap,
17131721
case BlockCaptureEntityKind::ARCStrong:
17141722
Str += "s";
17151723
break;
1724+
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
1725+
auto PtrAuth = CaptureTy.getPointerAuth();
1726+
assert(PtrAuth && PtrAuth.isAddressDiscriminated());
1727+
Str += "p" + llvm::to_string(PtrAuth.getKey()) + "d" +
1728+
llvm::to_string(PtrAuth.getExtraDiscriminator());
1729+
break;
1730+
}
17161731
case BlockCaptureEntityKind::BlockObject: {
17171732
const VarDecl *Var = CI.getVariable();
17181733
unsigned F = Flags.getBitMask();
@@ -1829,6 +1844,7 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
18291844
}
18301845
break;
18311846
}
1847+
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth:
18321848
case BlockCaptureEntityKind::None:
18331849
break;
18341850
}
@@ -1925,6 +1941,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
19251941
case BlockCaptureEntityKind::ARCWeak:
19261942
EmitARCCopyWeak(dstField, srcField);
19271943
break;
1944+
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
1945+
QualType Type = CI.getVariable()->getType();
1946+
PointerAuthQualifier PointerAuth = Type.getPointerAuth();
1947+
assert(PointerAuth && PointerAuth.isAddressDiscriminated());
1948+
EmitPointerAuthCopy(PointerAuth, Type, dstField, srcField);
1949+
// We don't need to push cleanups for ptrauth types.
1950+
continue;
1951+
}
19281952
case BlockCaptureEntityKind::NonTrivialCStruct: {
19291953
// If this is a C struct that requires non-trivial copy construction,
19301954
// emit a call to its copy constructor.
@@ -2261,6 +2285,33 @@ class CXXByrefHelpers final : public BlockByrefHelpers {
22612285
}
22622286
};
22632287

2288+
/// Emits the copy/dispose helpers for a __block variable with
2289+
/// address-discriminated pointer authentication.
2290+
class AddressDiscriminatedByrefHelpers final : public BlockByrefHelpers {
2291+
QualType VarType;
2292+
2293+
public:
2294+
AddressDiscriminatedByrefHelpers(CharUnits Alignment, QualType Type)
2295+
: BlockByrefHelpers(Alignment), VarType(Type) {
2296+
assert(Type.hasAddressDiscriminatedPointerAuth());
2297+
}
2298+
2299+
void emitCopy(CodeGenFunction &CGF, Address DestField,
2300+
Address SrcField) override {
2301+
CGF.EmitPointerAuthCopy(VarType.getPointerAuth(), VarType, DestField,
2302+
SrcField);
2303+
}
2304+
2305+
bool needsDispose() const override { return false; }
2306+
void emitDispose(CodeGenFunction &CGF, Address Field) override {
2307+
llvm_unreachable("should never be called");
2308+
}
2309+
2310+
void profileImpl(llvm::FoldingSetNodeID &ID) const override {
2311+
ID.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
2312+
}
2313+
};
2314+
22642315
/// Emits the copy/dispose helpers for a __block variable that is a non-trivial
22652316
/// C struct.
22662317
class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers {
@@ -2462,7 +2513,10 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
24622513
return ::buildByrefHelpers(
24632514
CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr));
24642515
}
2465-
2516+
if (type.hasAddressDiscriminatedPointerAuth()) {
2517+
return ::buildByrefHelpers(
2518+
CGM, byrefInfo, AddressDiscriminatedByrefHelpers(valueAlignment, type));
2519+
}
24662520
// If type is a non-trivial C struct type that is non-trivial to
24672521
// destructly move or destroy, build the copy and dispose helpers.
24682522
if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct ||

clang/lib/CodeGen/CGBlocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class BlockByrefInfo {
146146
enum class BlockCaptureEntityKind {
147147
None,
148148
CXXRecord, // Copy or destroy
149+
AddressDiscriminatedPointerAuth,
149150
ARCWeak,
150151
ARCStrong,
151152
NonTrivialCStruct,

clang/lib/CodeGen/CGCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4857,7 +4857,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
48574857

48584858
if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
48594859
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue &&
4860-
!type->isArrayParameterType()) {
4860+
!type->isArrayParameterType() && !type.isNonTrivialToPrimitiveCopy()) {
48614861
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
48624862
assert(L.isSimple());
48634863
args.addUncopiedAggregate(L, type);

clang/lib/CodeGen/CGNonTrivialStruct.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,18 @@ struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
266266
this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
267267
llvm::to_string(getFieldSize(FD, FT, this->Ctx)));
268268
}
269+
270+
void visitPtrAuth(QualType FT, const FieldDecl *FD,
271+
CharUnits CurStructOffset) {
272+
this->appendStr("_pa");
273+
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
274+
this->appendStr(llvm::to_string(PtrAuth.getKey()) + "_");
275+
this->appendStr(llvm::to_string(PtrAuth.getExtraDiscriminator()) + "_");
276+
if (PtrAuth.authenticatesNullValues())
277+
this->appendStr("anv_");
278+
CharUnits FieldOffset = CurStructOffset + this->getFieldOffset(FD);
279+
this->appendStr(llvm::to_string(FieldOffset.getQuantity()));
280+
}
269281
};
270282

271283
struct GenDefaultInitializeFuncName
@@ -568,6 +580,13 @@ struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
568580
RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
569581
this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
570582
}
583+
void visitPtrAuth(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
584+
std::array<Address, 2> Addrs) {
585+
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
586+
Addrs[DstIdx] = this->getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
587+
Addrs[SrcIdx] = this->getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
588+
this->CGF->EmitPointerAuthCopy(PtrAuth, FT, Addrs[DstIdx], Addrs[SrcIdx]);
589+
}
571590
};
572591

573592
// These classes that emit the special functions for a non-trivial struct.

clang/lib/Sema/SemaChecking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9443,6 +9443,9 @@ struct SearchNonTrivialToCopyField
94439443
void visitARCWeak(QualType FT, SourceLocation SL) {
94449444
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
94459445
}
9446+
void visitPtrAuth(QualType FT, SourceLocation SL) {
9447+
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
9448+
}
94469449
void visitStruct(QualType FT, SourceLocation SL) {
94479450
for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields())
94489451
visit(FD->getType(), FD->getLocation());

clang/lib/Sema/SemaDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13395,6 +13395,12 @@ struct DiagNonTrivalCUnionCopyVisitor
1339513395
asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
1339613396
}
1339713397

13398+
void visitPtrAuth(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
13399+
if (InNonTrivialUnion)
13400+
S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
13401+
<< 1 << 2 << QT << FD->getName();
13402+
}
13403+
1339813404
void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
1339913405
const FieldDecl *FD, bool InNonTrivialUnion) {}
1340013406
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}

0 commit comments

Comments
 (0)