Skip to content

[clang] Ensure correct copying of records with authenticated fields #136783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 24, 2025
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
2 changes: 2 additions & 0 deletions clang/include/clang/AST/NonTrivialTypeVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ struct CopiedTypeVisitor {
return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
case QualType::PCK_ARCWeak:
return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
case QualType::PCK_PtrAuth:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: looks like the cases were sorted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed locally

return asDerived().visitPtrAuth(FT, std::forward<Ts>(Args)...);
case QualType::PCK_Struct:
return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
case QualType::PCK_Trivial:
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,9 @@ class QualType {
/// with the ARC __weak qualifier.
PCK_ARCWeak,

/// The type is an address-discriminated signed pointer type.
PCK_PtrAuth,

/// The type is a struct containing a field whose type is neither
/// PCK_Trivial nor PCK_VolatileTrivial.
/// Note that a C++ struct type does not necessarily match this; C++ copying
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8372,6 +8372,9 @@ bool ASTContext::BlockRequiresCopying(QualType Ty,
return true;
}

if (Ty.hasAddressDiscriminatedPointerAuth())
return true;

// The block needs copy/destroy helpers if Ty is non-trivial to destructively
// move or destroy.
if (Ty.isNonTrivialToPrimitiveDestructiveMove() || Ty.isDestructedType())
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,9 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type,
if (CanonicalType->isIncompleteType())
return false;

if (CanonicalType.hasAddressDiscriminatedPointerAuth())
return false;

// As an extension, Clang treats vector types as Scalar types.
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
return true;
Expand All @@ -2830,7 +2833,7 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type,
return ClassDecl->isTriviallyCopyable();
}
}
return true;
return !RT->getDecl()->isNonTrivialToPrimitiveCopy();
}
// No other types can match.
return false;
Expand Down Expand Up @@ -2968,6 +2971,8 @@ QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const {
case Qualifiers::OCL_Weak:
return PCK_ARCWeak;
default:
if (hasAddressDiscriminatedPointerAuth())
return PCK_PtrAuth;
return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial;
}
}
Expand Down
56 changes: 55 additions & 1 deletion clang/lib/CodeGen/CGBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
}

if (T.hasAddressDiscriminatedPointerAuth())
return std::make_pair(
BlockCaptureEntityKind::AddressDiscriminatedPointerAuth, Flags);

Flags = BLOCK_FIELD_IS_OBJECT;
bool isBlockPointer = T->isBlockPointerType();
if (isBlockPointer)
Expand All @@ -1611,6 +1615,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong
: BlockCaptureEntityKind::BlockObject,
Flags);
case QualType::PCK_PtrAuth:
return std::make_pair(
BlockCaptureEntityKind::AddressDiscriminatedPointerAuth,
BlockFieldFlags());
case QualType::PCK_Trivial:
case QualType::PCK_VolatileTrivial: {
if (!T->isObjCRetainableType())
Expand Down Expand Up @@ -1713,6 +1721,13 @@ static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap,
case BlockCaptureEntityKind::ARCStrong:
Str += "s";
break;
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
auto PtrAuth = CaptureTy.getPointerAuth();
assert(PtrAuth && PtrAuth.isAddressDiscriminated());
Str += "p" + llvm::to_string(PtrAuth.getKey()) + "d" +
llvm::to_string(PtrAuth.getExtraDiscriminator());
break;
}
case BlockCaptureEntityKind::BlockObject: {
const VarDecl *Var = CI.getVariable();
unsigned F = Flags.getBitMask();
Expand Down Expand Up @@ -1829,6 +1844,7 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
}
break;
}
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth:
case BlockCaptureEntityKind::None:
break;
}
Expand Down Expand Up @@ -1925,6 +1941,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
case BlockCaptureEntityKind::ARCWeak:
EmitARCCopyWeak(dstField, srcField);
break;
case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
QualType Type = CI.getVariable()->getType();
PointerAuthQualifier PointerAuth = Type.getPointerAuth();
assert(PointerAuth && PointerAuth.isAddressDiscriminated());
EmitPointerAuthCopy(PointerAuth, Type, dstField, srcField);
// We don't need to push cleanups for ptrauth types.
continue;
}
case BlockCaptureEntityKind::NonTrivialCStruct: {
// If this is a C struct that requires non-trivial copy construction,
// emit a call to its copy constructor.
Expand Down Expand Up @@ -2261,6 +2285,33 @@ class CXXByrefHelpers final : public BlockByrefHelpers {
}
};

/// Emits the copy/dispose helpers for a __block variable with
/// address-discriminated pointer authentication.
class AddressDiscriminatedByrefHelpers final : public BlockByrefHelpers {
QualType VarType;

public:
AddressDiscriminatedByrefHelpers(CharUnits Alignment, QualType Type)
: BlockByrefHelpers(Alignment), VarType(Type) {
assert(Type.hasAddressDiscriminatedPointerAuth());
}

void emitCopy(CodeGenFunction &CGF, Address DestField,
Address SrcField) override {
CGF.EmitPointerAuthCopy(VarType.getPointerAuth(), VarType, DestField,
SrcField);
}

bool needsDispose() const override { return false; }
void emitDispose(CodeGenFunction &CGF, Address Field) override {
llvm_unreachable("should never be called");
}

void profileImpl(llvm::FoldingSetNodeID &ID) const override {
ID.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
}
};

/// Emits the copy/dispose helpers for a __block variable that is a non-trivial
/// C struct.
class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers {
Expand Down Expand Up @@ -2462,7 +2513,10 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
return ::buildByrefHelpers(
CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr));
}

if (type.hasAddressDiscriminatedPointerAuth()) {
return ::buildByrefHelpers(
CGM, byrefInfo, AddressDiscriminatedByrefHelpers(valueAlignment, type));
}
// If type is a non-trivial C struct type that is non-trivial to
// destructly move or destroy, build the copy and dispose helpers.
if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct ||
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGBlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class BlockByrefInfo {
enum class BlockCaptureEntityKind {
None,
CXXRecord, // Copy or destroy
AddressDiscriminatedPointerAuth,
ARCWeak,
ARCStrong,
NonTrivialCStruct,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4857,7 +4857,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,

if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue &&
!type->isArrayParameterType()) {
!type->isArrayParameterType() && !type.isNonTrivialToPrimitiveCopy()) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
assert(L.isSimple());
args.addUncopiedAggregate(L, type);
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CodeGen/CGNonTrivialStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
llvm::to_string(getFieldSize(FD, FT, this->Ctx)));
}

void visitPtrAuth(QualType FT, const FieldDecl *FD,
CharUnits CurStructOffset) {
this->appendStr("_pa");
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
this->appendStr(llvm::to_string(PtrAuth.getKey()) + "_");
this->appendStr(llvm::to_string(PtrAuth.getExtraDiscriminator()) + "_");
if (PtrAuth.authenticatesNullValues())
this->appendStr("anv_");
CharUnits FieldOffset = CurStructOffset + this->getFieldOffset(FD);
this->appendStr(llvm::to_string(FieldOffset.getQuantity()));
}
};

struct GenDefaultInitializeFuncName
Expand Down Expand Up @@ -568,6 +580,13 @@ struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
}
void visitPtrAuth(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
std::array<Address, 2> Addrs) {
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
Addrs[DstIdx] = this->getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
Addrs[SrcIdx] = this->getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
this->CGF->EmitPointerAuthCopy(PtrAuth, FT, Addrs[DstIdx], Addrs[SrcIdx]);
}
};

// These classes that emit the special functions for a non-trivial struct.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9443,6 +9443,9 @@ struct SearchNonTrivialToCopyField
void visitARCWeak(QualType FT, SourceLocation SL) {
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
}
void visitPtrAuth(QualType FT, SourceLocation SL) {
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
}
void visitStruct(QualType FT, SourceLocation SL) {
for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields())
visit(FD->getType(), FD->getLocation());
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13395,6 +13395,12 @@ struct DiagNonTrivalCUnionCopyVisitor
asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}

void visitPtrAuth(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
if (InNonTrivialUnion)
S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
<< 1 << 2 << QT << FD->getName();
}

void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
const FieldDecl *FD, bool InNonTrivialUnion) {}
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
Expand Down
Loading
Loading