@@ -8350,14 +8350,16 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
83508350// / Handle the __ptrauth qualifier.
83518351static void HandlePtrAuthQualifier (ASTContext &Ctx, QualType &T,
83528352 const ParsedAttr &Attr, Sema &S) {
8353-
8354- assert ((Attr. getNumArgs () > 0 && Attr. getNumArgs () <= 3 ) &&
8355- " __ptrauth qualifier takes between 1 and 3 arguments " );
8353+ assert ((Attr. getNumArgs () > 0 && Attr. getNumArgs () <= 4 ) &&
8354+ " __ptrauth qualifier takes between 1 and 4 arguments " );
8355+ StringRef AttrName = Attr. getAttrName ()-> getName ( );
83568356 Expr *KeyArg = Attr.getArgAsExpr (0 );
83578357 Expr *IsAddressDiscriminatedArg =
83588358 Attr.getNumArgs () >= 2 ? Attr.getArgAsExpr (1 ) : nullptr ;
83598359 Expr *ExtraDiscriminatorArg =
83608360 Attr.getNumArgs () >= 3 ? Attr.getArgAsExpr (2 ) : nullptr ;
8361+ Expr *AuthenticationOptionsArg =
8362+ Attr.getNumArgs () >= 4 ? Attr.getArgAsExpr (3 ) : nullptr ;
83618363
83628364 unsigned Key;
83638365 if (S.checkConstantPointerAuthKey (KeyArg, Key)) {
@@ -8374,20 +8376,191 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83748376 IsInvalid |= !S.checkPointerAuthDiscriminatorArg (
83758377 ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator);
83768378
8377- if (IsInvalid) {
8378- Attr.setInvalid ();
8379- return ;
8379+ std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt ;
8380+ SourceRange AuthenticationModeRange;
8381+
8382+ if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors () ) {
8383+ std::string OptionsString;
8384+ bool IsInitialized = false ;
8385+ const StringLiteral *OptionsStringLiteral = dyn_cast<StringLiteral>(AuthenticationOptionsArg);
8386+ auto ReportEvaluationOfExpressionIfNeeded = [&](){
8387+ if (OptionsStringLiteral || !IsInitialized)
8388+ return ;
8389+ S.Diag (AuthenticationOptionsArg->getBeginLoc (),
8390+ diag::note_ptrauth_evaluating_options) << OptionsString << AuthenticationOptionsArg->getSourceRange ();
8391+ };
8392+ auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason, std::optional<char > InvalidCh, auto Location) {
8393+ S.Diag (AuthenticationOptionsArg->getExprLoc (),
8394+ diag::err_ptrauth_invalid_option)
8395+ << AttrName << Reason << Location << !!InvalidCh << (InvalidCh ? *InvalidCh : ' \0 ' );
8396+ Attr.setInvalid ();
8397+ ReportEvaluationOfExpressionIfNeeded ();
8398+ };
8399+ if (AuthenticationOptionsArg->isValueDependent () || AuthenticationOptionsArg->isTypeDependent ()) {
8400+ DiagnoseInvalidOptionsParameter (" is dependent" , std::nullopt , AuthenticationOptionsArg->getSourceRange ());
8401+ return ;
8402+ }
8403+ if (OptionsStringLiteral) {
8404+ if (OptionsStringLiteral->containsNonAsciiOrNull ()) {
8405+ DiagnoseInvalidOptionsParameter (" contains invalid characters" , std::nullopt , AuthenticationOptionsArg->getSourceRange ());
8406+ return ;
8407+ }
8408+ OptionsString = OptionsStringLiteral->getString ();
8409+ } else if (S.EvaluateAsString (AuthenticationOptionsArg, OptionsString, S.Context , Sema::StringEvaluationContext::PtrauthOptions, /* ErrorOnInvalidMessage=*/ false )) {
8410+ for (char Ch : OptionsString) {
8411+ if (!Ch || !isascii (Ch)) {
8412+ DiagnoseInvalidOptionsParameter (" contains invalid characters" , Ch, AuthenticationOptionsArg->getSourceRange ());
8413+ return ;
8414+ }
8415+ }
8416+ } else {
8417+ Attr.setInvalid ();
8418+ return ;
8419+ }
8420+ IsInitialized = true ;
8421+ bool HasSeenOption = false ;
8422+ unsigned CurrentIdx = 0 ;
8423+
8424+ auto OptionStringIdxLocation = [&](unsigned Idx) {
8425+ if (OptionsStringLiteral)
8426+ return OptionsStringLiteral->getLocationOfByte (Idx, Ctx.getSourceManager (), Ctx.getLangOpts (), Ctx.getTargetInfo ());
8427+ return AuthenticationOptionsArg->getBeginLoc ();
8428+ };
8429+ auto OptionStringRange = [&](unsigned StartIdx, unsigned EndIdx) {
8430+ if (!OptionsStringLiteral)
8431+ return AuthenticationOptionsArg->getSourceRange ();
8432+ return SourceRange (OptionStringIdxLocation (StartIdx),
8433+ OptionStringIdxLocation (EndIdx));
8434+ };
8435+ auto NextOption = [&]() -> std::optional<std::pair<unsigned , unsigned >> {
8436+ auto ConsumeChar = [&](auto Filter) -> char {
8437+ if (CurrentIdx >= OptionsString.size ())
8438+ return 0 ;
8439+ char Current = OptionsString[CurrentIdx];
8440+ if (!Filter (Current))
8441+ return 0 ;
8442+ ++CurrentIdx;
8443+ return Current;
8444+ };
8445+ auto SkipWhiteSpace = [&]() {
8446+ while (ConsumeChar (isWhitespace)) {
8447+ // this space is intentionally left blank
8448+ }
8449+ };
8450+ auto MatchCharacter = [](char MatchChar) {
8451+ return [MatchChar](char Ch){ return MatchChar == Ch; };
8452+ };
8453+ SkipWhiteSpace ();
8454+ if (CurrentIdx == OptionsString.size ())
8455+ return std::nullopt ;
8456+ if (HasSeenOption) {
8457+ if (!ConsumeChar (MatchCharacter (' ,' ))) {
8458+ SourceLocation ErrorLocation = OptionStringIdxLocation (CurrentIdx);
8459+ S.Diag (ErrorLocation, diag::err_ptrauth_option_missing_comma)
8460+ << AttrName << ErrorLocation;
8461+ ReportEvaluationOfExpressionIfNeeded ();
8462+ return std::nullopt ;
8463+ }
8464+ SkipWhiteSpace ();
8465+ }
8466+ HasSeenOption = true ;
8467+ if (CurrentIdx == OptionsString.size ()) {
8468+ SourceLocation ErrorLocation = OptionStringIdxLocation (CurrentIdx);
8469+ S.Diag (ErrorLocation, diag::err_ptrauth_unexpected_option_end)
8470+ << AttrName << ErrorLocation;
8471+ ReportEvaluationOfExpressionIfNeeded ();
8472+ }
8473+ unsigned OptionStartIdx = CurrentIdx;
8474+ while (ConsumeChar (isalpha) || ConsumeChar (MatchCharacter (' -' ))) {
8475+ // this space is intentionally left blank
8476+ }
8477+ unsigned OptionEndIdx = CurrentIdx;
8478+ if (OptionStartIdx == OptionEndIdx) {
8479+ StringRef ErrorString (&OptionsString[CurrentIdx], 1 );
8480+ SourceLocation ErrorLocation = OptionStringIdxLocation (OptionStartIdx);
8481+ S.Diag (ErrorLocation, diag::err_ptrauth_option_unexpected_token) << ErrorString << AttrName << ErrorLocation;
8482+ ReportEvaluationOfExpressionIfNeeded ();
8483+ IsInvalid = true ;
8484+ return std::nullopt ;
8485+ }
8486+ return std::make_pair (OptionStartIdx, OptionEndIdx);
8487+ };
8488+
8489+ auto OptionHandler = [&](StringRef TokenStr, SourceRange TokenRange,
8490+ auto Value, auto *Option, SourceRange *OptionRange) {
8491+ SourceRange DiagnosedRange = TokenRange;
8492+ if (!OptionsStringLiteral)
8493+ DiagnosedRange = AuthenticationOptionsArg->getSourceRange ();
8494+ if (!*Option) {
8495+ *Option = Value;
8496+ *OptionRange = DiagnosedRange;
8497+ return true ;
8498+ }
8499+ bool IsAuthenticationMode =
8500+ std::is_same_v<decltype (Value), PointerAuthenticationMode>;
8501+ S.Diag (OptionRange->getBegin (), diag::err_ptrauth_repeated_authentication_option)
8502+ << AttrName << !IsAuthenticationMode << *OptionRange;
8503+ IsInvalid = true ;
8504+ if (OptionsStringLiteral)
8505+ S.Diag (OptionRange->getBegin (),
8506+ diag::note_ptrauth_previous_authentication_option)
8507+ << AttrName << !IsAuthenticationMode << *OptionRange;
8508+ return false ;
8509+ };
8510+ llvm::DenseMap<StringRef, std::function<bool (llvm::StringRef, SourceRange)>> OptionHandlers = {
8511+ {PointerAuthenticationOptionStrip,
8512+ [&](StringRef TokenStr, SourceRange Range) {
8513+ return OptionHandler (TokenStr, Range,
8514+ PointerAuthenticationMode::Strip,
8515+ &AuthenticationMode, &AuthenticationModeRange);
8516+ }},
8517+ {PointerAuthenticationOptionSignAndStrip,
8518+ [&](StringRef TokenStr, SourceRange Range) {
8519+ return OptionHandler (TokenStr, Range,
8520+ PointerAuthenticationMode::SignAndStrip,
8521+ &AuthenticationMode, &AuthenticationModeRange);
8522+ }},
8523+ {PointerAuthenticationOptionSignAndAuth,
8524+ [&](StringRef TokenStr, SourceRange Range) {
8525+ return OptionHandler (TokenStr, Range,
8526+ PointerAuthenticationMode::SignAndAuth,
8527+ &AuthenticationMode, &AuthenticationModeRange);
8528+ }}};
8529+ while (std::optional<std::pair<unsigned , unsigned >> Option = NextOption ()) {
8530+ StringRef OptionString (&OptionsString[Option->first ],
8531+ Option->second - Option->first );
8532+ SourceRange OptionRange = OptionStringRange (Option->first ,
8533+ Option->second );
8534+ auto Handler = OptionHandlers.find (OptionString);
8535+ if (Handler == OptionHandlers.end ()) {
8536+ S.Diag (OptionStringIdxLocation (Option->first ),
8537+ diag::err_ptrauth_unknown_authentication_option)
8538+ << AttrName << OptionString << OptionRange;
8539+ IsInvalid = true ;
8540+ break ;
8541+ }
8542+ if (!Handler->second (OptionString, OptionRange)) {
8543+ IsInvalid = true ;
8544+ break ;
8545+ }
8546+ }
83808547 }
83818548
83828549 if (!T->isSignableType () && !T->isDependentType ()) {
83838550 S.Diag (Attr.getLoc (), diag::err_ptrauth_qualifier_nonpointer) << T;
8551+ IsInvalid = true ;
8552+ }
8553+
8554+ if (IsInvalid) {
83848555 Attr.setInvalid ();
83858556 return ;
83868557 }
8558+ if (!AuthenticationMode)
8559+ AuthenticationMode = PointerAuthenticationMode::SignAndAuth;
83878560
83888561 if (T.getPointerAuth ()) {
83898562 S.Diag (Attr.getLoc (), diag::err_ptrauth_qualifier_redundant)
8390- << T << Attr. getAttrName ()-> getName () ;
8563+ << T << AttrName ;
83918564 Attr.setInvalid ();
83928565 return ;
83938566 }
0 commit comments