https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/137580
>From 07b6275740646c6ac0ffd95518e7e9fa8f1e8717 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Sun, 27 Apr 2025 22:33:44 -0700 Subject: [PATCH 1/2] [clang] Add support for __ptrauth being applied to integer types This adds support for the __ptrauth qualifier to be applied to pointer sized integer types. --- clang/docs/PointerAuthentication.rst | 11 +- clang/include/clang/AST/Type.h | 12 +- .../clang/Basic/DiagnosticSemaKinds.td | 10 +- clang/lib/AST/ASTContext.cpp | 3 + clang/lib/AST/Type.cpp | 6 + clang/lib/CodeGen/CGExprConstant.cpp | 4 + clang/lib/CodeGen/CGExprScalar.cpp | 2 +- clang/lib/CodeGen/CGPointerAuth.cpp | 17 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaType.cpp | 10 +- clang/lib/Sema/TreeTransform.h | 12 +- .../ptrauth-restricted-intptr-qualifier.c | 219 ++++++++++++++++++ clang/test/Sema/ptrauth-qualifier.c | 6 +- clang/test/SemaCXX/ptrauth-triviality.cpp | 48 ++++ 14 files changed, 329 insertions(+), 33 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index 41818d43ac687..b9341a9c3b6a8 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -284,13 +284,14 @@ __ptrauth Qualifier ^^^^^^^^^^^^^^^^^^^ ``__ptrauth(key, address, discriminator)`` is an extended type -qualifier which causes so-qualified objects to hold pointers signed using the -specified schema rather than the default schema for such types. +qualifier which causes so-qualified objects to hold pointers or pointer sized +integers signed using the specified schema rather than the default schema for +such types. In the current implementation in Clang, the qualified type must be a C pointer -type, either to a function or to an object. It currently cannot be an -Objective-C pointer type, a C++ reference type, or a block pointer type; these -restrictions may be lifted in the future. +type, either to a function or to an object, or a pointer sized integer. It +currently cannot be an Objective-C pointer type, a C++ reference type, or a +block pointer type; these restrictions may be lifted in the future. The qualifier's operands are as follows: diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 773796a55eaa1..435a9de68f774 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2560,7 +2560,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } bool isPointerType() const; bool isPointerOrReferenceType() const; - bool isSignableType() const; + bool isSignableType(const ASTContext &Ctx) const; + bool isSignablePointerType() const; + bool isSignableIntegerType(const ASTContext &Ctx) const; bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isCountAttributedType() const; bool isBlockPointerType() const; @@ -8222,7 +8224,13 @@ inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } -inline bool Type::isSignableType() const { return isPointerType(); } +inline bool Type::isSignableType(const ASTContext &Ctx) const { + return isSignablePointerType() || isSignableIntegerType(Ctx); +} + +inline bool Type::isSignablePointerType() const { + return isPointerType() || isObjCClassType() || isObjCQualifiedClassType(); +} inline bool Type::isBlockPointerType() const { return isa<BlockPointerType>(CanonicalType); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e1b9ed0647bb9..034ef4ff57187 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1031,10 +1031,12 @@ def err_ptrauth_qualifier_invalid : Error< "%select{return type|parameter type|property}1 may not be qualified with '__ptrauth'; type is %0">; def err_ptrauth_qualifier_cast : Error< "cannot cast to '__ptrauth'-qualified type %0">; -def err_ptrauth_qualifier_nonpointer : Error< - "'__ptrauth' qualifier only applies to pointer types; %0 is invalid">; -def err_ptrauth_qualifier_redundant : Error< - "type %0 is already %1-qualified">; +def err_ptrauth_qualifier_invalid_target + : Error<"'__ptrauth' qualifier only applies to pointer or pointer sized " + "integer" + " types; %0 is invalid">; +def err_ptrauth_qualifier_redundant + : Error<"type %0 is already __ptrauth-qualified">; def err_ptrauth_arg_not_ice : Error< "argument to '__ptrauth' must be an integer constant expression">; def err_ptrauth_address_discrimination_invalid : Error< diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 1ed16748dff1a..93c77638e5310 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2943,6 +2943,9 @@ bool ASTContext::hasUniqueObjectRepresentations( // All integrals and enums are unique. if (Ty->isIntegralOrEnumerationType()) { + // Address discriminated integer types are not unique. + if (Ty.hasAddressDiscriminatedPointerAuth()) + return false; // Except _BitInt types that have padding bits. if (const auto *BIT = Ty->getAs<BitIntType>()) return getTypeSize(BIT) == BIT->getNumBits(); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 31e4bcd7535ea..0776d228a07ec 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5062,6 +5062,12 @@ AttributedType::stripOuterNullability(QualType &T) { return std::nullopt; } +bool Type::isSignableIntegerType(const ASTContext &Ctx) const { + if (!isIntegralType(Ctx) || isEnumeralType()) + return false; + return Ctx.getTypeSize(this) == Ctx.getTypeSize(Ctx.VoidPtrTy); +} + bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { const auto *objcPtr = getAs<ObjCObjectPointerType>(); if (!objcPtr) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index b21ebeee4bed1..ebe6bb80504b5 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2444,6 +2444,10 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType, EnablePtrAuthFunctionTypeDiscrimination) .tryEmit(); case APValue::Int: + if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth(); + PointerAuth && + (PointerAuth.authenticatesNullValues() || Value.getInt() != 0)) + return nullptr; return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt()); case APValue::FixedPoint: return llvm::ConstantInt::get(CGM.getLLVMContext(), diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index f639a87e3ad0b..b15e4d64744ae 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2300,7 +2300,7 @@ static bool isLValueKnownNonNull(CodeGenFunction &CGF, const Expr *E) { } bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) { - assert(E->getType()->isSignableType()); + assert(E->getType()->isSignableType(getContext())); E = E->IgnoreParens(); diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 474848c8324f3..bf22912988d38 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -175,7 +175,7 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) { /// pointer type. static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM, QualType PointerType) { - assert(PointerType->isSignableType()); + assert(PointerType->isSignableType(CGM.getContext())); // Block pointers are currently not signed. if (PointerType->isBlockPointerType()) @@ -209,7 +209,7 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, /// needlessly resigning the pointer. std::pair<llvm::Value *, CGPointerAuthInfo> CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { - assert(E->getType()->isSignableType()); + assert(E->getType()->isSignableType(getContext())); E = E->IgnoreParens(); if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) { @@ -291,7 +291,10 @@ static bool equalAuthPolicies(const CGPointerAuthInfo &Left, if (Left.isSigned() != Right.isSigned()) return false; return Left.getKey() == Right.getKey() && - Left.getAuthenticationMode() == Right.getAuthenticationMode(); + Left.getAuthenticationMode() == Right.getAuthenticationMode() && + Left.isIsaPointer() == Right.isIsaPointer() && + Left.authenticatesNullValues() == Right.authenticatesNullValues() && + Left.getDiscriminator() == Right.getDiscriminator(); } // Return the discriminator or return zero if the discriminator is null. @@ -642,10 +645,10 @@ llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr, QualType SourceType, QualType DestType) { CGPointerAuthInfo CurAuthInfo, NewAuthInfo; - if (SourceType->isSignableType()) + if (SourceType->isSignableType(getContext())) CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); - if (DestType->isSignableType()) + if (DestType->isSignableType(getContext())) NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); if (!CurAuthInfo && !NewAuthInfo) @@ -667,10 +670,10 @@ Address CodeGenFunction::authPointerToPointerCast(Address Ptr, QualType SourceType, QualType DestType) { CGPointerAuthInfo CurAuthInfo, NewAuthInfo; - if (SourceType->isSignableType()) + if (SourceType->isSignableType(getContext())) CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); - if (DestType->isSignableType()) + if (DestType->isSignableType(getContext())) NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); if (!CurAuthInfo && !NewAuthInfo) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7cce7ed1fa054..cbccb567e2adf 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10888,7 +10888,7 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { return; } - // Ill-formed if the field is an address-discriminated pointer. + // Ill-formed if the field is an address-discriminated value. if (FT.hasAddressDiscriminatedPointerAuth()) { PrintDiagAndRemoveAttr(6); return; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 294daef70c339..a8e85c885069e 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8379,15 +8379,14 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, return; } - if (!T->isSignableType() && !T->isDependentType()) { - S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T; + if (!T->isSignableType(Ctx) && !T->isDependentType()) { + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target) << T; Attr.setInvalid(); return; } if (T.getPointerAuth()) { - S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) - << T << Attr.getAttrName()->getName(); + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) << T; Attr.setInvalid(); return; } @@ -8402,7 +8401,8 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, "address discriminator arg should be either 0 or 1"); PointerAuthQualifier Qual = PointerAuthQualifier::Create( Key, IsAddressDiscriminated, ExtraDiscriminator, - PointerAuthenticationMode::SignAndAuth, false, false); + PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false, + /*AuthenticatesNullValues=*/false); T = S.Context.getPointerAuthType(T, Qual); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8b4b79c6ec039..97d62d15a2c25 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5305,13 +5305,15 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T, PointerAuthQualifier LocalPointerAuth = Quals.getPointerAuth(); if (LocalPointerAuth.isPresent()) { if (T.getPointerAuth().isPresent()) { - SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant) - << TL.getType() << "__ptrauth"; - return QualType(); - } else if (!T->isSignableType() && !T->isDependentType()) { - SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_nonpointer) << T; + SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant) << TL.getType(); return QualType(); } + if (!T->isDependentType()) { + if (!T->isSignableType(SemaRef.getASTContext())) { + SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target) << T; + return QualType(); + } + } } // C++ [dcl.fct]p7: // [When] adding cv-qualifications on top of the function type [...] the diff --git a/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c new file mode 100644 index 0000000000000..dcce5764e2217 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c @@ -0,0 +1,219 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -O0 -o - | FileCheck %s + +#define __ptrauth(...) __ptrauth(__VA_ARGS__) + +__INTPTR_TYPE__ __ptrauth(1, 0, 56) g1 = 0; +// CHECK: @g1 = global i64 0 +__INTPTR_TYPE__ __ptrauth(1, 1, 1272) g2 = 0; +// CHECK: @g2 = global i64 0 +extern __UINTPTR_TYPE__ test_int; +__UINTPTR_TYPE__ __ptrauth(3, 1, 23) g3 = (__UINTPTR_TYPE__)&test_int; +// CHECK: @test_int = external global i64 +// CHECK: @g3 = global i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 3, i64 23, ptr @g3) to i64) + +__INTPTR_TYPE__ __ptrauth(1, 1, 712) ga[3] = {0,0,(__UINTPTR_TYPE__)&test_int}; + +// CHECK: @ga = global [3 x i64] [i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 712, ptr getelementptr inbounds ([3 x i64], ptr @ga, i32 0, i32 2)) to i64)] + +struct A { + __INTPTR_TYPE__ __ptrauth(1, 0, 431) f0; + __INTPTR_TYPE__ __ptrauth(1, 0, 9182) f1; + __INTPTR_TYPE__ __ptrauth(1, 0, 783) f2; +}; + +struct A gs1 = {0, 0, (__UINTPTR_TYPE__)&test_int}; +// CHECK: @gs1 = global %struct.A { i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 783) to i64) } + +struct B { + __INTPTR_TYPE__ __ptrauth(1, 1, 1276) f0; + __INTPTR_TYPE__ __ptrauth(1, 1, 23674) f1; + __INTPTR_TYPE__ __ptrauth(1, 1, 163) f2; +}; + +struct B gs2 = {0, 0, (__UINTPTR_TYPE__)&test_int}; +// CHECK: @gs2 = global %struct.B { i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 163, ptr getelementptr inbounds (%struct.B, ptr @gs2, i32 0, i32 2)) to i64) } + +// CHECK-LABEL: i64 @test_read_globals +__INTPTR_TYPE__ test_read_globals() { + __INTPTR_TYPE__ result = g1 + g2 + g3; + // CHECK: [[A:%.*]] = load i64, ptr @g1 + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[A]], i32 1, i64 56) + // CHECK: [[B:%.*]] = load i64, ptr @g2 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @g2 to i64), i64 1272) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[B]], i32 1, i64 [[BLENDED]]) + // CHECK: [[VALUE:%.*]] = load i64, ptr @g3 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @g3 to i64), i64 23) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 3, i64 [[BLENDED]]) + + for (int i = 0; i < 3; i++) { + result += ga[i]; + } + // CHECK: for.cond: + // CHECK: [[TEMP:%.*]] = load i32, ptr [[IDX_ADDR:%.*]] + + // CHECK: for.body: + // CHECK: [[IDX:%.*]] = load i32, ptr [[IDX_ADDR]] + // CHECK: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64 + // CHECK: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x i64], ptr @ga, i64 0, i64 [[IDXPROM]] + // CHECK: [[VALUE:%.*]] = load i64, ptr [[ARRAYIDX]] + // CHECK: [[CASTIDX:%.*]] = ptrtoint ptr [[ARRAYIDX]] to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTIDX]], i64 712) + // CHECK: resign.nonnull6: + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) + // CHECK: resign.cont7 + + result += gs1.f0 + gs1.f1 + gs1.f2; + // CHECK: resign.cont10: + // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.A, ptr @gs1, i32 0, i32 1 + // CHECK: resign.nonnull11: + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 9182) + // CHECK: resign.cont12: + // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.A, ptr @gs1, i32 0, i32 2) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 783) + result += gs2.f0 + gs2.f1 + gs2.f2; + // CHECK: [[ADDR:%.*]] = load i64, ptr @gs2 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @gs2 to i64), i64 1276) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 [[BLENDED]]) + // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 1) + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 1) to i64), i64 23674) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 [[BLENDED]]) + // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 2) + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 2) to i64), i64 163) + + return result; +} + +// CHECK-LABEL: void @test_write_globals +void test_write_globals(int i, __INTPTR_TYPE__ j) { + g1 = i; + g2 = j; + g3 = 0; + ga[0] = i; + ga[1] = j; + ga[2] = 0; + gs1.f0 = i; + gs1.f1 = j; + gs1.f2 = 0; + gs2.f0 = i; + gs2.f1 = j; + gs2.f2 = 0; +} + +// CHECK-LABEL: define void @test_set_A +void test_set_A(struct A *a, __INTPTR_TYPE__ x, int y) { + a->f0 = x; + // CHECK: [[XADDR:%.*]] = load i64, ptr %x.addr + // CHECK: [[SIGNED_X:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[XADDR]], i32 1, i64 431) + a->f1 = y; + // CHECK: [[Y:%.*]] = load i32, ptr %y.addr + // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64 + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, i64 9182) + a->f2 = 0; + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: [[F2:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 2 + // CHECK: store i64 0, ptr [[F2]] +} + +// CHECK-LABEL: define void @test_set_B +void test_set_B(struct B *b, __INTPTR_TYPE__ x, int y) { + b->f0 = x; + // CHECK: [[X:%.*]] = load i64, ptr %x.addr + // CHECK: [[F0_ADDR:%.*]] = ptrtoint ptr %f0 to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[F0_ADDR]], i64 1276) + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[X]], i32 1, i64 [[BLENDED]]) + b->f1 = y; + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr + // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 1 + // CHECK: [[Y:%.*]] = load i32, ptr %y.addr, align 4 + // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64 + // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[F1_ADDR]] to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 23674) + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, i64 [[BLENDED]]) + b->f2 = 0; + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr + // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 2 + // CHECK: store i64 0, ptr [[F2_ADDR]] +} + +// CHECK-LABEL: define i64 @test_get_A +__INTPTR_TYPE__ test_get_A(struct A *a) { + return a->f0 + a->f1 + a->f2; + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: [[F0_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 0 + // CHECK: [[F0:%.*]] = load i64, ptr [[F0_ADDR]] + // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F0]], i32 1, i64 431) + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 1 + // CHECK: [[F1:%.*]] = load i64, ptr [[F1_ADDR]] + // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F1]], i32 1, i64 9182) + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 2 + // CHECK: [[F2:%.*]] = load i64, ptr [[F2_ADDR]] + // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F2]], i32 1, i64 783) +} + +// CHECK-LABEL: define i64 @test_get_B +__INTPTR_TYPE__ test_get_B(struct B *b) { + return b->f0 + b->f1 + b->f2; + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr + // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 0 + // CHECK: [[VALUE:%.*]] = load i64, ptr [[F0]] + // CHECK: [[CASTF0:%.*]] = ptrtoint ptr %f0 to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF0]], i64 1276) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr + // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 1 + // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]] + // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 23674) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr + // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 2 + // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]] + // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 163) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) +} + +// CHECK-LABEL: define void @test_resign +void test_resign(struct A* a, const struct B *b) { + a->f0 = b->f0; + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr, align 8 + // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 0 + // CHECK: [[B:%.*]] = load ptr, ptr %b.addr, align 8 + // CHECK: [[F01:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 0 + // CHECK: [[F01VALUE:%.*]] = load i64, ptr [[F01]] + // CHECK: [[CASTF01:%.*]] = ptrtoint ptr %f01 to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF01]], i64 1276) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[F01VALUE]], i32 1, i64 [[BLENDED]], i32 1, i64 431) +} + +// CHECK-LABEL: define i64 @other_test +__INTPTR_TYPE__ other_test(__INTPTR_TYPE__ i) { + __INTPTR_TYPE__ __ptrauth(1, 1, 42) j = 0; + // CHECK: [[J_ADDR:%.*]] = ptrtoint ptr %j to i64 + // CHECK: store i64 0, ptr %j + __INTPTR_TYPE__ __ptrauth(1, 1, 43) k = 1234; + // CHECK: [[ADDR:%.*]] = ptrtoint ptr %k to i64 + // CHECK: [[JBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 43) + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 1234, i32 1, i64 [[JBLENDED]]) + __INTPTR_TYPE__ __ptrauth(1, 1, 44) l = i; + // CHECK: [[I:%.*]] = load i64, ptr %i.addr + // CHECK: [[ADDR:%.*]] = ptrtoint ptr %l to i64 + // CHECK: [[LBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 44) + // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[I]], i32 1, i64 [[LBLENDED]]) + asm volatile ("" ::: "memory"); + return j + k + l; + // CHECK: [[VALUE:%.*]] = load i64, ptr %j + // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr %j to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 42) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) + // CHECK: [[VALUE:%.*]] = load i64, ptr %k + // CHECK: [[CASTK:%.*]] = ptrtoint ptr %k to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTK]], i64 43) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) + // CHECK: [[VALUE:%.*]] = load i64, ptr %l + // CHECK: [[CASTL:%.*]] = ptrtoint ptr %l to i64 + // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTL]], i64 44) + // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]]) +} diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index 2ec4471e519ca..a45c52957d770 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -24,8 +24,8 @@ typedef int *intp; int nonConstantGlobal = 5; __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify a valid pointer authentication key for the current target}} -__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} -__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} +__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int' is invalid}} +__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int' is invalid}} int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected identifier or '('}} expected-error{{expected ')'}} expected-note {{to match this '('}} int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}} int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error {{invalid address discrimination flag '2'; '__ptrauth' requires '0' or '1'}} @@ -102,7 +102,7 @@ __attribute__((overloadable)) float overload_func(int * __ptrauth(VALID_DATA_KEY static_assert(_Generic(typeof(overload_func(&ptr0)), int : 1, default : 0)); static_assert(_Generic(typeof(overload_func(&valid0)), float : 1, default : 0)); -void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int[10]' is invalid}} +void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int[10]' is invalid}} struct S0 { // expected-note 4 {{struct S0' has subobjects that are non-trivial to copy}} intp __ptrauth(1, 1, 50) f0; // expected-note 4 {{f0 has type '__ptrauth(1,1,50) intp' (aka 'int *__ptrauth(1,1,50)') that is non-trivial to copy}} diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp b/clang/test/SemaCXX/ptrauth-triviality.cpp index 785e83aaaa545..60d1b57230f18 100644 --- a/clang/test/SemaCXX/ptrauth-triviality.cpp +++ b/clang/test/SemaCXX/ptrauth-triviality.cpp @@ -3,6 +3,8 @@ #define AQ __ptrauth(1,1,50) #define IQ __ptrauth(1,0,50) +#define AQ_IP __ptrauth(1,1,50) +#define IQ_IP __ptrauth(1,0,50) #define AA [[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]] #define IA [[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,type_discrimination)]] #define PA [[clang::ptrauth_vtable_pointer(process_dependent,no_address_discrimination,no_extra_discrimination)]] @@ -134,3 +136,49 @@ static_assert(!__is_trivially_copyable(Holder<S5>)); static_assert(__is_trivially_relocatable(Holder<S5>)); // expected-warning{{deprecated}} static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S5>)); static_assert(!__is_trivially_equality_comparable(Holder<S5>)); + +struct S6 { + __INTPTR_TYPE__ AQ_IP p_; + void *payload_; + bool operator==(const S6&) const = default; +}; +static_assert(__is_trivially_constructible(S6)); +static_assert(!__is_trivially_constructible(S6, const S6&)); +static_assert(!__is_trivially_assignable(S6, const S6&)); +static_assert(__is_trivially_destructible(S6)); +static_assert(!__is_trivially_copyable(S6)); +static_assert(!__is_trivially_relocatable(S6)); // expected-warning{{deprecated}} +static_assert(!__builtin_is_cpp_trivially_relocatable(S6)); +static_assert(!__is_trivially_equality_comparable(S6)); + +static_assert(__is_trivially_constructible(Holder<S6>)); +static_assert(!__is_trivially_constructible(Holder<S6>, const Holder<S6>&)); +static_assert(!__is_trivially_assignable(Holder<S6>, const Holder<S6>&)); +static_assert(__is_trivially_destructible(Holder<S6>)); +static_assert(!__is_trivially_copyable(Holder<S6>)); +static_assert(!__is_trivially_relocatable(Holder<S6>)); // expected-warning{{deprecated}} +static_assert(!__builtin_is_cpp_trivially_relocatable(Holder<S6>)); +static_assert(!__is_trivially_equality_comparable(Holder<S6>)); + +struct S7 { + __INTPTR_TYPE__ IQ_IP p_; + void *payload_; + bool operator==(const S7&) const = default; +}; +static_assert(__is_trivially_constructible(S7)); +static_assert(__is_trivially_constructible(S7, const S7&)); +static_assert(__is_trivially_assignable(S7&, const S7&)); +static_assert(__is_trivially_destructible(S7)); +static_assert(__is_trivially_copyable(S7)); +static_assert(__is_trivially_relocatable(S7)); // expected-warning{{deprecated}} +static_assert(__builtin_is_cpp_trivially_relocatable(S7)); +static_assert(__is_trivially_equality_comparable(S7)); + +static_assert(__is_trivially_constructible(Holder<S7>)); +static_assert(__is_trivially_constructible(Holder<S7>, const Holder<S7>&)); +static_assert(__is_trivially_assignable(Holder<S7>, const Holder<S7>&)); +static_assert(__is_trivially_destructible(Holder<S7>)); +static_assert(__is_trivially_copyable(Holder<S7>)); +static_assert(__is_trivially_relocatable(Holder<S7>)); // expected-warning{{deprecated}} +static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S7>)); +static_assert(__is_trivially_equality_comparable(Holder<S7>)); >From 0879a5f2e98d4228310cbac9686c57ae3262b46c Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Fri, 9 May 2025 11:48:58 -0700 Subject: [PATCH 2/2] Address punctuation and layout of diagnostics --- .../include/clang/Basic/DiagnosticSemaKinds.td | 17 +++++++++-------- clang/test/Sema/ptrauth-qualifier.c | 2 +- .../SemaCXX/ptrauth-template-parameters.cpp | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 034ef4ff57187..89b2d664d66a0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1028,21 +1028,22 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error< // __ptrauth qualifier def err_ptrauth_qualifier_invalid : Error< - "%select{return type|parameter type|property}1 may not be qualified with '__ptrauth'; type is %0">; + "%select{return type|parameter type|property}1 may not be qualified with " + "'__ptrauth'; type is %0">; def err_ptrauth_qualifier_cast : Error< "cannot cast to '__ptrauth'-qualified type %0">; -def err_ptrauth_qualifier_invalid_target - : Error<"'__ptrauth' qualifier only applies to pointer or pointer sized " - "integer" - " types; %0 is invalid">; -def err_ptrauth_qualifier_redundant - : Error<"type %0 is already __ptrauth-qualified">; +def err_ptrauth_qualifier_invalid_target : Error< + "'__ptrauth' qualifier only applies to pointer or pointer sized integer " + "types; %0 is invalid">; +def err_ptrauth_qualifier_redundant: Error< + "type %0 is already '__ptrauth'-qualified">; def err_ptrauth_arg_not_ice : Error< "argument to '__ptrauth' must be an integer constant expression">; def err_ptrauth_address_discrimination_invalid : Error< "invalid address discrimination flag '%0'; '__ptrauth' requires '0' or '1'">; def err_ptrauth_extra_discriminator_invalid : Error< - "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">; + "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between " + "'0' and '%1'">; /// main() // static main() is not an error in C, just in C++. diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index a45c52957d770..5d932b724f07a 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -27,7 +27,7 @@ __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify a __ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int' is invalid}} __ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int' is invalid}} int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected identifier or '('}} expected-error{{expected ')'}} expected-note {{to match this '('}} -int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}} +int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // expected-error{{type 'int *__ptrauth(2,0,0)' is already '__ptrauth'-qualified}} int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error {{invalid address discrimination flag '2'; '__ptrauth' requires '0' or '1'}} int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error {{invalid address discrimination flag '-1'; '__ptrauth' requires '0' or '1'}} int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error {{invalid extra discriminator flag '-1'; '__ptrauth' requires a value between '0' and '65535'}} diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp index ee23d3f2ec456..99899ad11dbe5 100644 --- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -3,7 +3,7 @@ template <typename T> struct G { T __ptrauth(0,0,1234) test; - // expected-error@-1 2 {{type '__ptrauth(0,0,1234) T' is already __ptrauth-qualified}} + // expected-error@-1 2 {{type '__ptrauth(0,0,1234) T' is already '__ptrauth'-qualified}} }; template <typename T> struct Indirect { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits