https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/136828
>From b3de41c15edc527154e461e5b0df61642599b45e Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 23 Apr 2025 01:43:00 -0700 Subject: [PATCH 1/2] [clang][ptrauth] add support for options parameter to __ptrauth This PR adds support for an 'options' parameter for the __ptrauth qualifier. The initial version only exposes the authehntication modes: * "strip" * "sign-and-strip" * "sign-and-auth" There are other options that will be added in future, but for now these are the modes already representable by PointerAuthQualifier. The initial support for authentication mode controls exist to support ABI changes over time, and as a byproduct support basic initial tests for option parsing. --- clang/include/clang/Basic/Attr.td | 3 +- .../clang/Basic/DiagnosticParseKinds.td | 2 +- .../clang/Basic/DiagnosticSemaKinds.td | 22 +- clang/include/clang/Basic/LangOptions.h | 6 + clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Sema/SemaType.cpp | 187 +++++++++++++- clang/test/CodeGen/ptrauth-stripping.c | 234 ++++++++++++++++++ clang/test/Parser/ptrauth-qualifier.c | 2 +- clang/test/Sema/ptrauth-qualifier-options.c | 28 +++ clang/test/Sema/ptrauth-qualifier.c | 69 ++++++ 11 files changed, 543 insertions(+), 14 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-stripping.c create mode 100644 clang/test/Sema/ptrauth-qualifier-options.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index d48aed5b73cf5..27c01c7b36877 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3568,7 +3568,8 @@ def PointerAuth : TypeAttr { let Spellings = [CustomKeyword<"__ptrauth">]; let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>, - IntArgument<"ExtraDiscriminator", 1>]; + IntArgument<"ExtraDiscriminator", 1>, + StringArgument<"Options", 1>]; let Documentation = [PtrAuthDocs]; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9975520f4f9ff..4424a1eba5bcd 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1722,7 +1722,7 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning< InGroup<CudaCompat>; def err_ptrauth_qualifier_bad_arg_count : Error< - "'__ptrauth' qualifier must take between 1 and 3 arguments">; + "'__ptrauth' qualifier must take between 1 and 4 arguments">; def warn_cuda_attr_lambda_position : Warning< "nvcc does not allow '__%0__' to appear after the parameter list in lambdas">, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c562802efba57..5021b2a7112f2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1036,6 +1036,24 @@ def err_ptrauth_address_discrimination_invalid : Error< def err_ptrauth_extra_discriminator_invalid : Error< "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">; +// __ptrauth qualifier options string +def note_ptrauth_evaluating_options + : Note<"options parameter evaluated to '%0'">; +def err_ptrauth_invalid_option + : Error<"'%0' options parameter %1">; +def err_ptrauth_unknown_authentication_option + : Error<"unknown '%0' authentication option '%1'">; +def err_ptrauth_repeated_authentication_option + : Error<"repeated '%0' authentication %select{mode|option}1">; +def note_ptrauth_previous_authentication_option + : Note<"previous '%0' authentication %select{mode|option}1">; +def err_ptrauth_unexpected_option_end + : Error<"unexpected end of options parameter for %0">; +def err_ptrauth_option_unexpected_token + : Error<"unexpected character '%0' in '%1' options">; +def err_ptrauth_option_missing_comma + : Error<"missing comma between '%0' options">; + /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, @@ -1728,8 +1746,8 @@ def note_expr_evaluates_to : Note< def subst_user_defined_msg : TextSubstitution< - "%select{the message|the expression}0 in " - "%select{a static assertion|this asm operand}0">; + "%select{the message|the expression|the expression}0 in " + "%select{a static assertion|this asm operand|a pointer authentication option}0">; def err_user_defined_msg_invalid : Error< "%sub{subst_user_defined_msg}0 must be a string literal or an " diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index bbebf7af9ede3..388371a91c7f4 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -65,6 +65,12 @@ enum class PointerAuthenticationMode : unsigned { SignAndAuth }; +static constexpr llvm::StringLiteral PointerAuthenticationOptionStrip = "strip"; +static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndStrip = + "sign-and-strip"; +static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndAuth = + "sign-and-auth"; + /// Bitfields of LangOptions, split out from LangOptions in order to ensure that /// this large collection of bitfields is a trivial class type. class LangOptionsBase { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 96d81e618494a..469eec5354284 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5691,7 +5691,7 @@ class Sema final : public SemaBase { void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); - enum class StringEvaluationContext { StaticAssert = 0, Asm = 1 }; + enum class StringEvaluationContext { StaticAssert = 0, Asm = 1, PtrauthOptions = 2 }; bool EvaluateAsString(Expr *Message, APValue &Result, ASTContext &Ctx, StringEvaluationContext EvalContext, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 69d40baaf4298..60d7ac98866f8 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3427,7 +3427,7 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) { T.consumeClose(); SourceLocation EndLoc = T.getCloseLocation(); - if (ArgExprs.empty() || ArgExprs.size() > 3) { + if (ArgExprs.empty() || ArgExprs.size() > 4) { Diag(KwLoc, diag::err_ptrauth_qualifier_bad_arg_count); return; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6e7ee8b5506ff..fbb8a94e5a3f4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8350,14 +8350,16 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, /// Handle the __ptrauth qualifier. static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, const ParsedAttr &Attr, Sema &S) { - - assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 3) && - "__ptrauth qualifier takes between 1 and 3 arguments"); + assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 4) && + "__ptrauth qualifier takes between 1 and 4 arguments"); + StringRef AttrName = Attr.getAttrName()->getName(); Expr *KeyArg = Attr.getArgAsExpr(0); Expr *IsAddressDiscriminatedArg = Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr; Expr *ExtraDiscriminatorArg = Attr.getNumArgs() >= 3 ? Attr.getArgAsExpr(2) : nullptr; + Expr *AuthenticationOptionsArg = + Attr.getNumArgs() >= 4 ? Attr.getArgAsExpr(3) : nullptr; unsigned Key; if (S.checkConstantPointerAuthKey(KeyArg, Key)) { @@ -8374,20 +8376,191 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, IsInvalid |= !S.checkPointerAuthDiscriminatorArg( ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator); - if (IsInvalid) { - Attr.setInvalid(); - return; + std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt; + SourceRange AuthenticationModeRange; + + if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors() ) { + std::string OptionsString; + bool IsInitialized = false; + const StringLiteral *OptionsStringLiteral = dyn_cast<StringLiteral>(AuthenticationOptionsArg); + auto ReportEvaluationOfExpressionIfNeeded = [&](){ + if (OptionsStringLiteral || !IsInitialized) + return; + S.Diag(AuthenticationOptionsArg->getBeginLoc(), + diag::note_ptrauth_evaluating_options) << OptionsString << AuthenticationOptionsArg->getSourceRange(); + }; + auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason, std::optional<char> InvalidCh, auto Location) { + S.Diag(AuthenticationOptionsArg->getExprLoc(), + diag::err_ptrauth_invalid_option) + << AttrName << Reason << Location << !!InvalidCh << (InvalidCh ? *InvalidCh : '\0'); + Attr.setInvalid(); + ReportEvaluationOfExpressionIfNeeded(); + }; + if (AuthenticationOptionsArg->isValueDependent() || AuthenticationOptionsArg->isTypeDependent()) { + DiagnoseInvalidOptionsParameter("is dependent", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + return; + } + if (OptionsStringLiteral) { + if (OptionsStringLiteral->containsNonAsciiOrNull()) { + DiagnoseInvalidOptionsParameter("contains invalid characters", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + return; + } + OptionsString = OptionsStringLiteral->getString(); + } else if (S.EvaluateAsString(AuthenticationOptionsArg, OptionsString, S.Context, Sema::StringEvaluationContext::PtrauthOptions, /*ErrorOnInvalidMessage=*/false)) { + for (char Ch : OptionsString) { + if (!Ch || !isascii(Ch)) { + DiagnoseInvalidOptionsParameter("contains invalid characters", Ch, AuthenticationOptionsArg->getSourceRange()); + return; + } + } + } else { + Attr.setInvalid(); + return; + } + IsInitialized = true; + bool HasSeenOption = false; + unsigned CurrentIdx = 0; + + auto OptionStringIdxLocation = [&](unsigned Idx) { + if (OptionsStringLiteral) + return OptionsStringLiteral->getLocationOfByte(Idx, Ctx.getSourceManager(), Ctx.getLangOpts(), Ctx.getTargetInfo()); + return AuthenticationOptionsArg->getBeginLoc(); + }; + auto OptionStringRange = [&](unsigned StartIdx, unsigned EndIdx) { + if (!OptionsStringLiteral) + return AuthenticationOptionsArg->getSourceRange(); + return SourceRange(OptionStringIdxLocation(StartIdx), + OptionStringIdxLocation(EndIdx)); + }; + auto NextOption = [&]() -> std::optional<std::pair<unsigned, unsigned>> { + auto ConsumeChar = [&](auto Filter) -> char { + if (CurrentIdx >= OptionsString.size()) + return 0; + char Current = OptionsString[CurrentIdx]; + if (!Filter(Current)) + return 0; + ++CurrentIdx; + return Current; + }; + auto SkipWhiteSpace = [&]() { + while (ConsumeChar(isWhitespace)) { + // this space is intentionally left blank + } + }; + auto MatchCharacter = [](char MatchChar) { + return [MatchChar](char Ch){ return MatchChar == Ch; }; + }; + SkipWhiteSpace(); + if (CurrentIdx == OptionsString.size()) + return std::nullopt; + if (HasSeenOption) { + if (!ConsumeChar(MatchCharacter(','))) { + SourceLocation ErrorLocation = OptionStringIdxLocation(CurrentIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_option_missing_comma) + << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + return std::nullopt; + } + SkipWhiteSpace(); + } + HasSeenOption = true; + if (CurrentIdx == OptionsString.size()) { + SourceLocation ErrorLocation = OptionStringIdxLocation(CurrentIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_unexpected_option_end) + << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + } + unsigned OptionStartIdx = CurrentIdx; + while (ConsumeChar(isalpha) || ConsumeChar(MatchCharacter('-'))) { + // this space is intentionally left blank + } + unsigned OptionEndIdx = CurrentIdx; + if (OptionStartIdx == OptionEndIdx) { + StringRef ErrorString(&OptionsString[CurrentIdx], 1); + SourceLocation ErrorLocation = OptionStringIdxLocation(OptionStartIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_option_unexpected_token) << ErrorString << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + IsInvalid = true; + return std::nullopt; + } + return std::make_pair(OptionStartIdx, OptionEndIdx); + }; + + auto OptionHandler = [&](StringRef TokenStr, SourceRange TokenRange, + auto Value, auto *Option, SourceRange *OptionRange) { + SourceRange DiagnosedRange = TokenRange; + if (!OptionsStringLiteral) + DiagnosedRange = AuthenticationOptionsArg->getSourceRange(); + if (!*Option) { + *Option = Value; + *OptionRange = DiagnosedRange; + return true; + } + bool IsAuthenticationMode = + std::is_same_v<decltype(Value), PointerAuthenticationMode>; + S.Diag(OptionRange->getBegin(), diag::err_ptrauth_repeated_authentication_option) + << AttrName << !IsAuthenticationMode << *OptionRange; + IsInvalid = true; + if (OptionsStringLiteral) + S.Diag(OptionRange->getBegin(), + diag::note_ptrauth_previous_authentication_option) + << AttrName << !IsAuthenticationMode << *OptionRange; + return false; + }; + llvm::DenseMap<StringRef, std::function<bool(llvm::StringRef, SourceRange)>> OptionHandlers = { + {PointerAuthenticationOptionStrip, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler(TokenStr, Range, + PointerAuthenticationMode::Strip, + &AuthenticationMode, &AuthenticationModeRange); + }}, + {PointerAuthenticationOptionSignAndStrip, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler(TokenStr, Range, + PointerAuthenticationMode::SignAndStrip, + &AuthenticationMode, &AuthenticationModeRange); + }}, + {PointerAuthenticationOptionSignAndAuth, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler(TokenStr, Range, + PointerAuthenticationMode::SignAndAuth, + &AuthenticationMode, &AuthenticationModeRange); + }}}; + while (std::optional<std::pair<unsigned, unsigned>> Option = NextOption()) { + StringRef OptionString(&OptionsString[Option->first], + Option->second - Option->first); + SourceRange OptionRange = OptionStringRange(Option->first, + Option->second); + auto Handler = OptionHandlers.find(OptionString); + if (Handler == OptionHandlers.end()) { + S.Diag(OptionStringIdxLocation(Option->first), + diag::err_ptrauth_unknown_authentication_option) + << AttrName << OptionString << OptionRange; + IsInvalid = true; + break; + } + if (!Handler->second(OptionString, OptionRange)) { + IsInvalid = true; + break; + } + } } if (!T->isSignableType() && !T->isDependentType()) { S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T; + IsInvalid = true; + } + + if (IsInvalid) { Attr.setInvalid(); return; } + if (!AuthenticationMode) + AuthenticationMode = PointerAuthenticationMode::SignAndAuth; if (T.getPointerAuth()) { S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) - << T << Attr.getAttrName()->getName(); + << T << AttrName; Attr.setInvalid(); return; } diff --git a/clang/test/CodeGen/ptrauth-stripping.c b/clang/test/CodeGen/ptrauth-stripping.c new file mode 100644 index 0000000000000..dce07030a902e --- /dev/null +++ b/clang/test/CodeGen/ptrauth-stripping.c @@ -0,0 +1,234 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s + +typedef void *NonePointer; +typedef void *__ptrauth(1, 1, 101, "strip") StripPointer; +typedef void *__ptrauth(1, 1, 102, "sign-and-strip") SignAndStripPointer; +typedef void *__ptrauth(1, 1, 103, "sign-and-auth") SignAndAuthPointer; +typedef __UINT64_TYPE__ NoneIntptr; + +NonePointer globalNonePointer = "foo0"; +StripPointer globalStripPointer = "foo1"; +SignAndStripPointer globalSignAndStripPointer = "foo2"; +SignAndAuthPointer globalSignAndAuthPointer = "foo3"; +NoneIntptr globalNoneIntptr = (__UINT64_TYPE__)&globalNonePointer; + +// CHECK: @.str = private unnamed_addr constant [5 x i8] c"foo0\00", align 1 +// CHECK: @globalNonePointer = global ptr @.str, align 8 +// CHECK: @.str.1 = private unnamed_addr constant [5 x i8] c"foo1\00", align 1 +// CHECK: @globalStripPointer = global ptr @.str.1, align 8 +// CHECK: @.str.2 = private unnamed_addr constant [5 x i8] c"foo2\00", align 1 +// CHECK: @globalSignAndStripPointer = global ptr ptrauth (ptr @.str.2, i32 1, i64 102, ptr @globalSignAndStripPointer), align 8 +// CHECK: @.str.3 = private unnamed_addr constant [5 x i8] c"foo3\00", align 1 +// CHECK: @globalSignAndAuthPointer = global ptr ptrauth (ptr @.str.3, i32 1, i64 103, ptr @globalSignAndAuthPointer), align 8 +// CHECK: @globalNoneIntptr = global i64 ptrtoint (ptr @globalNonePointer to i64), align 8 + +typedef struct { + NonePointer ptr; + NoneIntptr i; +} NoneStruct; +typedef struct { + StripPointer ptr; +} StripStruct; +typedef struct { + SignAndStripPointer ptr; +} SignAndStripStruct; +typedef struct { + SignAndAuthPointer ptr; +} SignAndAuthStruct; + +// CHECK-LABEL: @testNone +NoneStruct testNone(NoneStruct *a, NoneStruct *b, NoneStruct c) { + globalNonePointer += 1; + // CHECK: [[GLOBALP:%.*]] = load ptr, ptr @globalNonePointer + // CHECK: [[GLOBALPP:%.*]] = getelementptr inbounds i8, ptr [[GLOBALP]], i64 1 + // CHECK: store ptr [[GLOBALPP]], ptr @globalNonePointer + globalNoneIntptr += 1; + // CHECK: [[GLOBALI:%.*]] = load i64, ptr @globalNoneIntptr + // CHECK: [[GLOBALIP:%.*]] = add i64 [[GLOBALI]], 1 + // CHECK: store i64 [[GLOBALIP]], ptr @globalNoneIntptr + a->ptr += 1; + // CHECK: [[PTR:%.*]] = load ptr, ptr %a.addr, align 8 + // CHECK: [[I_PTR:%.*]] = getelementptr inbounds nuw %struct.NoneStruct, ptr [[PTR]], i32 0, i32 1 + // CHECK: [[I:%.*]] = load i64, ptr [[I_PTR]], align 8 + // CHECK: [[IP:%.*]] = add i64 [[I]], 1 + // CHECK: store i64 [[IP]], ptr [[I_PTR]], align 8 + *b = *a; + // CHECK: [[B_ADDR:%.*]] = load ptr, ptr %b.addr, align 8 + // CHECK: [[A_ADDR:%.*]] = load ptr, ptr %a.addr, align 8 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[B_ADDR]], ptr align 8 [[A_ADDR]], i64 16, i1 false) + return c; +} + +// CHECK-LABEL: @testStrip1 +void testStrip1() { + globalStripPointer += 1; + // CHECK: [[GLOBALP:%.*]] = load ptr, ptr @globalStripPointer + // CHECK: [[GLOBALPI:%.*]] = ptrtoint ptr [[GLOBALP]] to i64 + // CHECK: {{%.*}} = call i64 @llvm.ptrauth.strip(i64 [[GLOBALPI]], i32 1) +} +// CHECK-LABEL: @testStrip2 +void testStrip2(StripStruct *a) { + a->ptr += 1; + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: [[PTR:%.*]] = getelementptr inbounds nuw %struct.StripStruct, ptr [[A]], i32 0, i32 0 + // CHECK: [[APTR:%.*]] = load ptr, ptr [[PTR]] + // CHECK: [[APTRI:%.*]] = ptrtoint ptr [[APTR]] to i64 + // CHECK: {{%.*}} = call i64 @llvm.ptrauth.strip(i64 [[APTRI]], i32 1) +} +// CHECK-LABEL: @testStrip4 +void testStrip4(StripStruct *a, StripStruct *b) { + *b = *a; + // CHECK: call void @__copy_assignment_8_8_pa1_101_0_t8w8(ptr %0, ptr %1) +} + +// CHECK-LABEL: @testStrip5 +StripStruct testStrip5(StripStruct a) { + return a; + // CHECK: call void @__copy_constructor_8_8_pa1_101_0_t8w8(ptr %agg.result, ptr %a) +} + +// CHECK-LABEL: @testSignAndStrip1 +void testSignAndStrip1(void) { + globalSignAndStripPointer += 1; + // CHECK: [[GP:%.*]] = load ptr, ptr @globalSignAndStripPointer + // CHECK: [[GPI:%.*]] = ptrtoint ptr [[GP]] to i64 + // CHECK: [[STRIPPED:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[GPI]], i32 1) + // CHECK: [[STRIPPEDP:%.*]] = inttoptr i64 [[STRIPPED]] to ptr + // CHECK: [[PHI:%.*]] = phi ptr [ null, %entry ], [ [[STRIPPEDP]], %resign.nonnull ] + // CHECK: [[ADDPTR:%.*]] = getelementptr inbounds i8, ptr [[PHI]], i64 1 + // CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @globalSignAndStripPointer to i64), i64 102) + // CHECK: [[ADDPTRI:%.*]] = ptrtoint ptr [[ADDPTR]] to i64 + // CHECK: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 [[ADDPTRI]], i32 1, i64 [[DISC]]) +} + +// CHECK-LABEL: @testSignAndStrip2 +void testSignAndStrip2(SignAndStripStruct *a) { + a->ptr += 1; + // CHECK: [[A:%.*]] = load ptr, ptr %a.addr + // CHECK: %ptr = getelementptr inbounds nuw %struct.SignAndStripStruct, ptr [[A]], i32 0, i32 0 + // CHECK: [[APTR:%.*]] = load ptr, ptr %ptr + // CHECK: [[APTRI:%.*]] = ptrtoint ptr [[APTR]] to i64 + // CHECK: [[STRIPPED:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[APTRI]], i32 1) + // CHECK: [[STRIPPEDP:%.*]] = inttoptr i64 [[STRIPPED]] to ptr + // CHECK: [[PHI:%.*]] = phi ptr [ null, %entry ], [ [[STRIPPEDP]], %resign.nonnull ] + // CHECK: %add.ptr = getelementptr inbounds i8, ptr [[PHI]], i64 1 + // CHECK: [[PTRI:%.*]] = ptrtoint ptr %ptr to i64 + // CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[PTRI]], i64 102) + // CHECK: [[APTRI:%.*]] = ptrtoint ptr %add.ptr to i64 + // CHECK: call i64 @llvm.ptrauth.sign(i64 [[APTRI]], i32 1, i64 [[DISC]]) +} + +// CHECK-LABEL: @testSignAndStrip4 +void testSignAndStrip4(SignAndStripStruct *a, SignAndStripStruct *b) { + *b = *a; + // CHECK: call void @__copy_assignment_8_8_pa1_102_0_t8w8(ptr %0, ptr %1) +} + +// CHECK-LABEL: @testSignAndStrip5 +SignAndStripStruct testSignAndStrip5(SignAndStripStruct a) { + return a; + // CHECK: call void @__copy_constructor_8_8_pa1_102_0_t8w8(ptr %agg.result, ptr %a) +} + +// CHECK-LABEL: @testSignAndAuth1 +void testSignAndAuth1() { + globalSignAndAuthPointer += 1; + // CHECK: %0 = load ptr, ptr @globalSignAndAuthPointer + // CHECK: %1 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @globalSignAndAuthPointer to i64), i64 103) + // CHECK: %3 = ptrtoint ptr %0 to i64 + // CHECK: %4 = call i64 @llvm.ptrauth.auth(i64 %3, i32 1, i64 %1) + // CHECK: %5 = inttoptr i64 %4 to ptr + // CHECK: %6 = phi ptr [ null, %entry ], [ %5, %resign.nonnull ] + // CHECK: %add.ptr = getelementptr inbounds i8, ptr %6, i64 1 + // CHECK: %7 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @globalSignAndAuthPointer to i64), i64 103) + // CHECK: %8 = ptrtoint ptr %add.ptr to i64 + // CHECK: %9 = call i64 @llvm.ptrauth.sign(i64 %8, i32 1, i64 %7) +} + +// CHECK-LABEL: @testSignAndAuth3 +void testSignAndAuth3(SignAndAuthStruct *a) { + a->ptr += 1; + // CHECK: %0 = load ptr, ptr %a.addr + // CHECK: %ptr = getelementptr inbounds nuw %struct.SignAndAuthStruct, ptr %0, i32 0, i32 0 + // CHECK: %1 = load ptr, ptr %ptr + // CHECK: %2 = ptrtoint ptr %ptr to i64 + // CHECK: %3 = call i64 @llvm.ptrauth.blend(i64 %2, i64 103) + // CHECK: %5 = ptrtoint ptr %1 to i64 + // CHECK: %6 = call i64 @llvm.ptrauth.auth(i64 %5, i32 1, i64 %3) + // CHECK: %7 = inttoptr i64 %6 to ptr + // CHECK: %8 = phi ptr [ null, %entry ], [ %7, %resign.nonnull ] + // CHECK: %add.ptr = getelementptr inbounds i8, ptr %8, i64 1 + // CHECK: %9 = ptrtoint ptr %ptr to i64 + // CHECK: %10 = call i64 @llvm.ptrauth.blend(i64 %9, i64 103) + // CHECK: %11 = ptrtoint ptr %add.ptr to i64 + // CHECK: %12 = call i64 @llvm.ptrauth.sign(i64 %11, i32 1, i64 %10) +} + +// CHECK-LABEL: @testSignAndAuth4 +void testSignAndAuth4(SignAndAuthStruct *a, SignAndAuthStruct *b) { + *b = *a; + // CHECK: call void @__copy_assignment_8_8_pa1_103_0_t8w8(ptr %0, ptr %1) +} + +// CHECK-LABEL: @testSignAndAuth5 +SignAndAuthStruct testSignAndAuth5(SignAndAuthStruct a) { + return a; + // CHECK: call void @__copy_constructor_8_8_pa1_103_0_t8w8(ptr %agg.result, ptr %a) +} + +// CHECK-LABEL: @testCoercions1 +void testCoercions1(StripStruct *a, SignAndStripStruct *b) { + a->ptr = b->ptr; + // CHECK: %0 = load ptr, ptr %a.addr + // CHECK: %ptr = getelementptr inbounds nuw %struct.StripStruct, ptr %0, i32 0, i32 0 + // CHECK: %1 = load ptr, ptr %b.addr + // CHECK: %ptr1 = getelementptr inbounds nuw %struct.SignAndStripStruct, ptr %1, i32 0, i32 0 + // CHECK: %2 = load ptr, ptr %ptr1 + // CHECK: %3 = ptrtoint ptr %ptr1 to i64 + // CHECK: %4 = call i64 @llvm.ptrauth.blend(i64 %3, i64 102) + // CHECK: %8 = ptrtoint ptr %2 to i64 + // CHECK: %9 = call i64 @llvm.ptrauth.strip(i64 %8, i32 1) +} + +// CHECK-LABEL: @testCoercions2 +void testCoercions2(StripStruct *a, SignAndAuthStruct *b) { + b->ptr = a->ptr; + // CHECK: store ptr %a, ptr %a.addr + // CHECK: store ptr %b, ptr %b.addr + // CHECK: %0 = load ptr, ptr %b.addr + // CHECK: %ptr = getelementptr inbounds nuw %struct.SignAndAuthStruct, ptr %0, i32 0, i32 0 + // CHECK: %1 = load ptr, ptr %a.addr + // CHECK: %ptr1 = getelementptr inbounds nuw %struct.StripStruct, ptr %1, i32 0, i32 0 + // CHECK: %2 = load ptr, ptr %ptr1 + // CHECK: %3 = ptrtoint ptr %ptr1 to i64 + // CHECK: %4 = call i64 @llvm.ptrauth.blend(i64 %3, i64 101) + // CHECK: %5 = ptrtoint ptr %ptr to i64 + // CHECK: %6 = call i64 @llvm.ptrauth.blend(i64 %5, i64 103) + // CHECK: %7 = icmp ne ptr %2, null + // CHECK: %8 = ptrtoint ptr %2 to i64 + // CHECK: %9 = call i64 @llvm.ptrauth.strip(i64 %8, i32 1) + // CHECK: %10 = inttoptr i64 %9 to ptr + // CHECK: %11 = ptrtoint ptr %10 to i64 + // CHECK: %12 = call i64 @llvm.ptrauth.sign(i64 %11, i32 1, i64 %6) +} + +// CHECK-LABEL: @testCoercions3 +void testCoercions3(SignAndStripStruct *a, SignAndAuthStruct *b) { + a->ptr = b->ptr; + // CHECK: %0 = load ptr, ptr %a.addr + // CHECK: %ptr = getelementptr inbounds nuw %struct.SignAndStripStruct, ptr %0, i32 0, i32 0 + // CHECK: %1 = load ptr, ptr %b.addr + // CHECK: %ptr1 = getelementptr inbounds nuw %struct.SignAndAuthStruct, ptr %1, i32 0, i32 0 + // CHECK: %2 = load ptr, ptr %ptr1 + // CHECK: %3 = ptrtoint ptr %ptr1 to i64 + // CHECK: %4 = call i64 @llvm.ptrauth.blend(i64 %3, i64 103) + // CHECK: %5 = ptrtoint ptr %ptr to i64 + // CHECK: %6 = call i64 @llvm.ptrauth.blend(i64 %5, i64 102) + // CHECK: %8 = ptrtoint ptr %2 to i64 + // CHECK: %9 = call i64 @llvm.ptrauth.auth(i64 %8, i32 1, i64 %4) + // CHECK: %10 = inttoptr i64 %9 to ptr + // CHECK: %11 = ptrtoint ptr %10 to i64 + // CHECK: %12 = call i64 @llvm.ptrauth.sign(i64 %11, i32 1, i64 %6) + // CHECK: %13 = inttoptr i64 %12 to ptr + // CHECK: %14 = phi ptr [ null, %entry ], [ %13, %resign.nonnull ] +} diff --git a/clang/test/Parser/ptrauth-qualifier.c b/clang/test/Parser/ptrauth-qualifier.c index 2071ac6c2d661..014613e0a3bbd 100644 --- a/clang/test/Parser/ptrauth-qualifier.c +++ b/clang/test/Parser/ptrauth-qualifier.c @@ -15,4 +15,4 @@ int nonConstantGlobal = 5; __ptrauth int invalid0; // expected-error{{expected '('}} __ptrauth() int invalid1; // expected-error{{expected expression}} -int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12) invalid12; // expected-error{{qualifier must take between 1 and 3 arguments}} +int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12, 24) invalid12; // expected-error{{qualifier must take between 1 and 4 arguments}} diff --git a/clang/test/Sema/ptrauth-qualifier-options.c b/clang/test/Sema/ptrauth-qualifier-options.c new file mode 100644 index 0000000000000..712c508820459 --- /dev/null +++ b/clang/test/Sema/ptrauth-qualifier-options.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s + +_Static_assert(__has_extension(ptrauth_qualifier), "the ptrauth qualifier should be available"); + +#if __aarch64__ +#define VALID_CODE_KEY 0 +#define VALID_DATA_KEY 2 +#define INVALID_KEY 200 +#else +#error Provide these constants if you port this test +#endif + + +typedef int *intp; + +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip" + " isa-pointer") invalid24; // expected-error{{missing comma between '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip,\n,isa-pointer") invalid25; // expected-error{{unexpected character ',' in '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip,\t,isa-pointer") invalid26; // expected-error{{unexpected character ',' in '__ptrauth' options}} + +int *__ptrauth(VALID_DATA_KEY, 1, 0, "strip") valid12; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip") valid13; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-auth") valid14; +int *__ptrauth(VALID_DATA_KEY, 1, 0, " strip") valid22; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "strip ") valid23; +int *__ptrauth(VALID_DATA_KEY, 1, 0, " strip ") valid24; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "") valid29; diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index ab12acd8975f4..6cd8a2bf45c51 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s // RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s +#include <ptrauth.h> + #if !__has_extension(ptrauth_qualifier) // This error means that the __ptrauth qualifier availability test says that it // is not available. This error is not expected in the output, if it is seen @@ -36,6 +38,22 @@ int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-err int * __ptrauth(VALID_DATA_KEY, nonConstantGlobal, 1000) invalid13; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} int * __ptrauth(nonConstantGlobal, 1, 1000) invalid14; // expected-error{{expression is not an integer constant expression}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, 41) invalid11; // expected-error{{the expression in a pointer authentication option must be a string literal or an object with 'data()' and 'size()' member functions}} +int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error{{argument to '__ptrauth' must be an integer constant expression}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "Foo") invalid13; // expected-error{{unknown '__ptrauth' authentication option 'Foo'}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip", 41) invalid14; // expected-error{{'__ptrauth' qualifier must take between 1 and 4 arguments}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip,sign-and-strip") invalid15; // expected-error{{repeated '__ptrauth' authentication mode}} +// expected-note@-1{{previous '__ptrauth' authentication mode}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip,") invalid19; // expected-error{{unexpected end of options parameter for __ptrauth}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, ",") invalid20; // expected-error{{unexpected character ',' in '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, ",,") invalid21; // expected-error{{unexpected character ',' in '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip isa-pointer") invalid22; // expected-error{{missing comma between '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip\nisa-pointer") invalid23; // expected-error{{missing comma between '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 65535, "strip" + " isa-pointer") invalid24; // expected-error{{missing comma between '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip,\n,isa-pointer") invalid25; // expected-error{{unexpected character ',' in '__ptrauth' options}} +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip,\t,isa-pointer") invalid26; // expected-error{{unexpected character ',' in '__ptrauth' options}} + int * __ptrauth(VALID_DATA_KEY) valid0; int * __ptrauth(VALID_DATA_KEY) *valid1; __ptrauth(VALID_DATA_KEY) intp valid2; @@ -47,6 +65,13 @@ int * __ptrauth(VALID_DATA_KEY, 1) valid7; int * __ptrauth(VALID_DATA_KEY, (_Bool) 1) valid8; int * __ptrauth(VALID_DATA_KEY, 1, 0) valid9; int * __ptrauth(VALID_DATA_KEY, 1, 65535) valid10; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "strip") valid12; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-strip") valid13; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "sign-and-auth") valid14; +int *__ptrauth(VALID_DATA_KEY, 1, 0, " strip") valid22; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "strip ") valid23; +int *__ptrauth(VALID_DATA_KEY, 1, 0, " strip ") valid24; +int *__ptrauth(VALID_DATA_KEY, 1, 0, "") valid29; int * __ptrauth(VALID_DATA_KEY) array0[10]; int (* __ptrauth(VALID_DATA_KEY) array1)[10]; @@ -103,3 +128,47 @@ 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}} + +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}} +}; + +union U0 { // expected-note 4 {{union U0' has subobjects that are non-trivial to copy}} + struct S0 s0; +}; + +struct S1 { + intp __ptrauth(1, 0, 50) f0; +}; + +union U1 { + struct S1 s1; +}; + +union U2 { // expected-note 2 {{union U2' has subobjects that are non-trivial to copy}} + intp __ptrauth(1, 1, 50) f0; // expected-note 2 {{f0 has type '__ptrauth(1,1,50) intp' (aka 'int *__ptrauth(1,1,50)') that is non-trivial to copy}} + intp __ptrauth(1, 0, 50) f1; +}; + +// Test for r353556. +struct S2 { // expected-note 2 {{struct S2' has subobjects that are non-trivial to copy}} + intp __ptrauth(1, 1, 50) f0[4]; // expected-note 2 {{f0 has type '__ptrauth(1,1,50) intp' (aka 'int *__ptrauth(1,1,50)') that is non-trivial to copy}} +}; + +union U3 { // expected-note 2 {{union U3' has subobjects that are non-trivial to copy}} + struct S2 s2; +}; + +struct S4 { + union U0 u0; +}; + +union U0 foo0(union U0); // expected-error {{cannot use type 'union U0' for function/method return since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'union U0' for a function/method parameter since it is a union that is non-trivial to copy}} + +union U1 foo1(union U1); + +union U2 foo2(union U2); // expected-error {{cannot use type 'union U2' for function/method return since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'union U2' for a function/method parameter since it is a union that is non-trivial to copy}} + +union U3 foo3(union U3); // expected-error {{cannot use type 'union U3' for function/method return since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'union U3' for a function/method parameter since it is a union that is non-trivial to copy}} + +struct S4 foo4(struct S4); // expected-error {{cannot use type 'struct S4' for function/method return since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'struct S4' for a function/method parameter since it contains a union that is non-trivial to copy}} >From ca6766b36b02a48b30a66a53c71d972ef147ef27 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 23 Apr 2025 02:08:11 -0700 Subject: [PATCH 2/2] Oh style bot :D --- clang/include/clang/Basic/Attr.td | 3 +- .../clang/Basic/DiagnosticParseKinds.td | 4 +- .../clang/Basic/DiagnosticSemaKinds.td | 11 +- clang/include/clang/Sema/Sema.h | 6 +- clang/lib/Sema/SemaType.cpp | 105 +++++++++++------- 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 27c01c7b36877..e857bc5a803d3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3566,8 +3566,7 @@ def ObjCRequiresPropertyDefs : InheritableAttr { def PointerAuth : TypeAttr { let Spellings = [CustomKeyword<"__ptrauth">]; - let Args = [IntArgument<"Key">, - BoolArgument<"AddressDiscriminated", 1>, + let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>, IntArgument<"ExtraDiscriminator", 1>, StringArgument<"Options", 1>]; let Documentation = [PtrAuthDocs]; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 4424a1eba5bcd..2a639b38f3120 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1721,8 +1721,8 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning< "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">, InGroup<CudaCompat>; -def err_ptrauth_qualifier_bad_arg_count : Error< - "'__ptrauth' qualifier must take between 1 and 4 arguments">; +def err_ptrauth_qualifier_bad_arg_count + : Error<"'__ptrauth' qualifier must take between 1 and 4 arguments">; def warn_cuda_attr_lambda_position : Warning< "nvcc does not allow '__%0__' to appear after the parameter list in lambdas">, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5021b2a7112f2..a656a56cac68a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1039,8 +1039,7 @@ def err_ptrauth_extra_discriminator_invalid : Error< // __ptrauth qualifier options string def note_ptrauth_evaluating_options : Note<"options parameter evaluated to '%0'">; -def err_ptrauth_invalid_option - : Error<"'%0' options parameter %1">; +def err_ptrauth_invalid_option : Error<"'%0' options parameter %1">; def err_ptrauth_unknown_authentication_option : Error<"unknown '%0' authentication option '%1'">; def err_ptrauth_repeated_authentication_option @@ -1744,10 +1743,10 @@ def err_static_assert_requirement_failed : Error< def note_expr_evaluates_to : Note< "expression evaluates to '%0 %1 %2'">; - -def subst_user_defined_msg : TextSubstitution< - "%select{the message|the expression|the expression}0 in " - "%select{a static assertion|this asm operand|a pointer authentication option}0">; +def subst_user_defined_msg + : TextSubstitution<"%select{the message|the expression|the expression}0 in " + "%select{a static assertion|this asm operand|a pointer " + "authentication option}0">; def err_user_defined_msg_invalid : Error< "%sub{subst_user_defined_msg}0 must be a string literal or an " diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 469eec5354284..a379a271b47db 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5691,7 +5691,11 @@ class Sema final : public SemaBase { void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); - enum class StringEvaluationContext { StaticAssert = 0, Asm = 1, PtrauthOptions = 2 }; + enum class StringEvaluationContext { + StaticAssert = 0, + Asm = 1, + PtrauthOptions = 2 + }; bool EvaluateAsString(Expr *Message, APValue &Result, ASTContext &Ctx, StringEvaluationContext EvalContext, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index fbb8a94e5a3f4..9aa548ef6f9c7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8379,37 +8379,52 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt; SourceRange AuthenticationModeRange; - if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors() ) { + if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors()) { std::string OptionsString; bool IsInitialized = false; - const StringLiteral *OptionsStringLiteral = dyn_cast<StringLiteral>(AuthenticationOptionsArg); - auto ReportEvaluationOfExpressionIfNeeded = [&](){ + const StringLiteral *OptionsStringLiteral = + dyn_cast<StringLiteral>(AuthenticationOptionsArg); + auto ReportEvaluationOfExpressionIfNeeded = [&]() { if (OptionsStringLiteral || !IsInitialized) return; S.Diag(AuthenticationOptionsArg->getBeginLoc(), - diag::note_ptrauth_evaluating_options) << OptionsString << AuthenticationOptionsArg->getSourceRange(); + diag::note_ptrauth_evaluating_options) + << OptionsString << AuthenticationOptionsArg->getSourceRange(); }; - auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason, std::optional<char> InvalidCh, auto Location) { + auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason, + std::optional<char> InvalidCh, + auto Location) { S.Diag(AuthenticationOptionsArg->getExprLoc(), diag::err_ptrauth_invalid_option) - << AttrName << Reason << Location << !!InvalidCh << (InvalidCh ? *InvalidCh : '\0'); + << AttrName << Reason << Location << !!InvalidCh + << (InvalidCh ? *InvalidCh : '\0'); Attr.setInvalid(); ReportEvaluationOfExpressionIfNeeded(); }; - if (AuthenticationOptionsArg->isValueDependent() || AuthenticationOptionsArg->isTypeDependent()) { - DiagnoseInvalidOptionsParameter("is dependent", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + if (AuthenticationOptionsArg->isValueDependent() || + AuthenticationOptionsArg->isTypeDependent()) { + DiagnoseInvalidOptionsParameter( + "is dependent", std::nullopt, + AuthenticationOptionsArg->getSourceRange()); return; } if (OptionsStringLiteral) { if (OptionsStringLiteral->containsNonAsciiOrNull()) { - DiagnoseInvalidOptionsParameter("contains invalid characters", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + DiagnoseInvalidOptionsParameter( + "contains invalid characters", std::nullopt, + AuthenticationOptionsArg->getSourceRange()); return; } OptionsString = OptionsStringLiteral->getString(); - } else if (S.EvaluateAsString(AuthenticationOptionsArg, OptionsString, S.Context, Sema::StringEvaluationContext::PtrauthOptions, /*ErrorOnInvalidMessage=*/false)) { + } else if (S.EvaluateAsString(AuthenticationOptionsArg, OptionsString, + S.Context, + Sema::StringEvaluationContext::PtrauthOptions, + /*ErrorOnInvalidMessage=*/false)) { for (char Ch : OptionsString) { if (!Ch || !isascii(Ch)) { - DiagnoseInvalidOptionsParameter("contains invalid characters", Ch, AuthenticationOptionsArg->getSourceRange()); + DiagnoseInvalidOptionsParameter( + "contains invalid characters", Ch, + AuthenticationOptionsArg->getSourceRange()); return; } } @@ -8423,14 +8438,16 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, auto OptionStringIdxLocation = [&](unsigned Idx) { if (OptionsStringLiteral) - return OptionsStringLiteral->getLocationOfByte(Idx, Ctx.getSourceManager(), Ctx.getLangOpts(), Ctx.getTargetInfo()); + return OptionsStringLiteral->getLocationOfByte( + Idx, Ctx.getSourceManager(), Ctx.getLangOpts(), + Ctx.getTargetInfo()); return AuthenticationOptionsArg->getBeginLoc(); }; auto OptionStringRange = [&](unsigned StartIdx, unsigned EndIdx) { if (!OptionsStringLiteral) return AuthenticationOptionsArg->getSourceRange(); return SourceRange(OptionStringIdxLocation(StartIdx), - OptionStringIdxLocation(EndIdx)); + OptionStringIdxLocation(EndIdx)); }; auto NextOption = [&]() -> std::optional<std::pair<unsigned, unsigned>> { auto ConsumeChar = [&](auto Filter) -> char { @@ -8448,7 +8465,7 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, } }; auto MatchCharacter = [](char MatchChar) { - return [MatchChar](char Ch){ return MatchChar == Ch; }; + return [MatchChar](char Ch) { return MatchChar == Ch; }; }; SkipWhiteSpace(); if (CurrentIdx == OptionsString.size()) @@ -8457,7 +8474,7 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, if (!ConsumeChar(MatchCharacter(','))) { SourceLocation ErrorLocation = OptionStringIdxLocation(CurrentIdx); S.Diag(ErrorLocation, diag::err_ptrauth_option_missing_comma) - << AttrName << ErrorLocation; + << AttrName << ErrorLocation; ReportEvaluationOfExpressionIfNeeded(); return std::nullopt; } @@ -8478,7 +8495,8 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, if (OptionStartIdx == OptionEndIdx) { StringRef ErrorString(&OptionsString[CurrentIdx], 1); SourceLocation ErrorLocation = OptionStringIdxLocation(OptionStartIdx); - S.Diag(ErrorLocation, diag::err_ptrauth_option_unexpected_token) << ErrorString << AttrName << ErrorLocation; + S.Diag(ErrorLocation, diag::err_ptrauth_option_unexpected_token) + << ErrorString << AttrName << ErrorLocation; ReportEvaluationOfExpressionIfNeeded(); IsInvalid = true; return std::nullopt; @@ -8487,7 +8505,8 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, }; auto OptionHandler = [&](StringRef TokenStr, SourceRange TokenRange, - auto Value, auto *Option, SourceRange *OptionRange) { + auto Value, auto *Option, + SourceRange *OptionRange) { SourceRange DiagnosedRange = TokenRange; if (!OptionsStringLiteral) DiagnosedRange = AuthenticationOptionsArg->getSourceRange(); @@ -8497,40 +8516,42 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, return true; } bool IsAuthenticationMode = - std::is_same_v<decltype(Value), PointerAuthenticationMode>; - S.Diag(OptionRange->getBegin(), diag::err_ptrauth_repeated_authentication_option) + std::is_same_v<decltype(Value), PointerAuthenticationMode>; + S.Diag(OptionRange->getBegin(), + diag::err_ptrauth_repeated_authentication_option) << AttrName << !IsAuthenticationMode << *OptionRange; IsInvalid = true; if (OptionsStringLiteral) S.Diag(OptionRange->getBegin(), diag::note_ptrauth_previous_authentication_option) - << AttrName << !IsAuthenticationMode << *OptionRange; + << AttrName << !IsAuthenticationMode << *OptionRange; return false; }; - llvm::DenseMap<StringRef, std::function<bool(llvm::StringRef, SourceRange)>> OptionHandlers = { - {PointerAuthenticationOptionStrip, - [&](StringRef TokenStr, SourceRange Range) { - return OptionHandler(TokenStr, Range, - PointerAuthenticationMode::Strip, - &AuthenticationMode, &AuthenticationModeRange); - }}, - {PointerAuthenticationOptionSignAndStrip, - [&](StringRef TokenStr, SourceRange Range) { - return OptionHandler(TokenStr, Range, - PointerAuthenticationMode::SignAndStrip, - &AuthenticationMode, &AuthenticationModeRange); - }}, - {PointerAuthenticationOptionSignAndAuth, - [&](StringRef TokenStr, SourceRange Range) { - return OptionHandler(TokenStr, Range, - PointerAuthenticationMode::SignAndAuth, - &AuthenticationMode, &AuthenticationModeRange); - }}}; + llvm::DenseMap<StringRef, std::function<bool(llvm::StringRef, SourceRange)>> + OptionHandlers = { + {PointerAuthenticationOptionStrip, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler( + TokenStr, Range, PointerAuthenticationMode::Strip, + &AuthenticationMode, &AuthenticationModeRange); + }}, + {PointerAuthenticationOptionSignAndStrip, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler( + TokenStr, Range, PointerAuthenticationMode::SignAndStrip, + &AuthenticationMode, &AuthenticationModeRange); + }}, + {PointerAuthenticationOptionSignAndAuth, + [&](StringRef TokenStr, SourceRange Range) { + return OptionHandler( + TokenStr, Range, PointerAuthenticationMode::SignAndAuth, + &AuthenticationMode, &AuthenticationModeRange); + }}}; while (std::optional<std::pair<unsigned, unsigned>> Option = NextOption()) { StringRef OptionString(&OptionsString[Option->first], Option->second - Option->first); - SourceRange OptionRange = OptionStringRange(Option->first, - Option->second); + SourceRange OptionRange = + OptionStringRange(Option->first, Option->second); auto Handler = OptionHandlers.find(OptionString); if (Handler == OptionHandlers.end()) { S.Diag(OptionStringIdxLocation(Option->first), @@ -8560,7 +8581,7 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, if (T.getPointerAuth()) { S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) - << T << AttrName; + << T << AttrName; Attr.setInvalid(); return; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits