4848#include " llvm/IR/DerivedTypes.h"
4949#include " llvm/Support/ErrorHandling.h"
5050#include < bitset>
51+ #include < cctype>
5152#include < optional>
5253
5354using namespace clang ;
@@ -8350,14 +8351,16 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
83508351// / Handle the __ptrauth qualifier.
83518352static void HandlePtrAuthQualifier (ASTContext &Ctx, QualType &T,
83528353 const ParsedAttr &Attr, Sema &S) {
8353-
8354- assert ((Attr. getNumArgs () > 0 && Attr. getNumArgs () <= 3 ) &&
8355- " __ptrauth qualifier takes between 1 and 3 arguments " );
8354+ assert ((Attr. getNumArgs () > 0 && Attr. getNumArgs () <= 4 ) &&
8355+ " __ptrauth qualifier takes between 1 and 4 arguments " );
8356+ StringRef AttrName = Attr. getAttrName ()-> getName ( );
83568357 Expr *KeyArg = Attr.getArgAsExpr (0 );
83578358 Expr *IsAddressDiscriminatedArg =
83588359 Attr.getNumArgs () >= 2 ? Attr.getArgAsExpr (1 ) : nullptr ;
83598360 Expr *ExtraDiscriminatorArg =
83608361 Attr.getNumArgs () >= 3 ? Attr.getArgAsExpr (2 ) : nullptr ;
8362+ Expr *AuthenticationOptionsArg =
8363+ Attr.getNumArgs () >= 4 ? Attr.getArgAsExpr (3 ) : nullptr ;
83618364
83628365 unsigned Key;
83638366 if (S.checkConstantPointerAuthKey (KeyArg, Key)) {
@@ -8373,21 +8376,151 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83738376 IsAddressDiscriminated);
83748377 IsInvalid |= !S.checkPointerAuthDiscriminatorArg (
83758378 ExtraDiscriminatorArg, PointerAuthDiscArgKind::Extra, ExtraDiscriminator);
8379+ std::string LastAuthenticationMode;
8380+ std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt ;
8381+ bool IsIsaPointer = false ;
8382+ bool AuthenticatesNullValues = false ;
8383+
8384+ if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors ()) {
8385+ StringRef OptionsString;
8386+ std::string EvaluatedString;
8387+ bool HasEvaluatedOptionsString = false ;
8388+ const StringLiteral *OptionsStringLiteral =
8389+ dyn_cast<StringLiteral>(AuthenticationOptionsArg);
8390+ SourceRange AuthenticationOptionsRange =
8391+ AuthenticationOptionsArg->getSourceRange ();
8392+ bool ReportedEvaluation = false ;
8393+ auto ReportEvaluationOfExpressionIfNeeded = [&]() {
8394+ if (OptionsStringLiteral || !HasEvaluatedOptionsString ||
8395+ ReportedEvaluation)
8396+ return ;
8397+ ReportedEvaluation = true ;
8398+ S.Diag (AuthenticationOptionsRange.getBegin (),
8399+ diag::note_ptrauth_evaluating_options)
8400+ << OptionsString << AuthenticationOptionsRange;
8401+ };
8402+ auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason) {
8403+ S.Diag (AuthenticationOptionsRange.getBegin (),
8404+ diag::err_ptrauth_invalid_option)
8405+ << AttrName << Reason;
8406+ Attr.setInvalid ();
8407+ ReportEvaluationOfExpressionIfNeeded ();
8408+ };
8409+ if (AuthenticationOptionsArg->isValueDependent () ||
8410+ AuthenticationOptionsArg->isTypeDependent ()) {
8411+ DiagnoseInvalidOptionsParameter (" is dependent" );
8412+ return ;
8413+ }
8414+ if (OptionsStringLiteral) {
8415+ OptionsString = OptionsStringLiteral->getString ();
8416+ HasEvaluatedOptionsString = true ;
8417+ } else {
8418+ Expr::EvalResult Eval;
8419+ bool Result = AuthenticationOptionsArg->EvaluateAsRValue (Eval, Ctx);
8420+ if (Result && Eval.Val .isLValue ()) {
8421+ auto *BaseExpr = Eval.Val .getLValueBase ().dyn_cast <const Expr *>();
8422+ const StringLiteral *EvaluatedStringLiteral =
8423+ dyn_cast<StringLiteral>(const_cast <Expr *>(BaseExpr));
8424+ if (EvaluatedStringLiteral) {
8425+ CharUnits StartOffset = Eval.Val .getLValueOffset ();
8426+ EvaluatedString = EvaluatedStringLiteral->getString ().drop_front (
8427+ StartOffset.getQuantity ());
8428+ OptionsString = EvaluatedString;
8429+ HasEvaluatedOptionsString = true ;
8430+ }
8431+ }
8432+ }
8433+ if (!HasEvaluatedOptionsString) {
8434+ DiagnoseInvalidOptionsParameter (
8435+ " must be a string of comma separated flags" );
8436+ return ;
8437+ }
8438+ for (char Ch : OptionsString) {
8439+ if (Ch != ' -' && Ch != ' ,' && !isWhitespace (Ch) && !isalpha (Ch)) {
8440+ DiagnoseInvalidOptionsParameter (" contains invalid characters" );
8441+ return ;
8442+ }
8443+ }
8444+ HasEvaluatedOptionsString = true ;
8445+ OptionsString = OptionsString.trim ();
8446+ llvm::SmallVector<StringRef> Options;
8447+ if (!OptionsString.empty ())
8448+ OptionsString.split (Options, ' ,' );
8449+
8450+ auto OptionHandler = [&](auto Value, auto *Option,
8451+ std::string *LastOption = nullptr ) {
8452+ return [&, Value, Option, LastOption](StringRef OptionString) {
8453+ if (!*Option) {
8454+ *Option = Value;
8455+ if (LastOption)
8456+ *LastOption = OptionString;
8457+ return true ;
8458+ }
8459+ bool IsAuthenticationMode =
8460+ std::is_same_v<decltype (Value), PointerAuthenticationMode>;
8461+ S.Diag (AuthenticationOptionsRange.getBegin (),
8462+ diag::err_ptrauth_repeated_authentication_option)
8463+ << AttrName << !IsAuthenticationMode << OptionString
8464+ << (LastOption ? *LastOption : " " );
8465+ return false ;
8466+ };
8467+ };
83768468
8377- if (IsInvalid) {
8378- Attr.setInvalid ();
8379- return ;
8469+ for (unsigned Idx = 0 ; Idx < Options.size (); ++Idx) {
8470+ StringRef Option = Options[Idx].trim ();
8471+ if (Option.empty ()) {
8472+ bool IsLastOption = Idx == (Options.size () - 1 );
8473+ DiagnoseInvalidOptionsParameter (
8474+ IsLastOption ? " has a trailing comma" : " contains an empty option" );
8475+ continue ;
8476+ }
8477+ auto SelectedHandler =
8478+ llvm::StringSwitch<std::function<bool (StringRef)>>(Option)
8479+ .Case (PointerAuthenticationOptionStrip,
8480+ OptionHandler (PointerAuthenticationMode::Strip,
8481+ &AuthenticationMode, &LastAuthenticationMode))
8482+ .Case (PointerAuthenticationOptionSignAndStrip,
8483+ OptionHandler (PointerAuthenticationMode::SignAndStrip,
8484+ &AuthenticationMode, &LastAuthenticationMode))
8485+ .Case (PointerAuthenticationOptionSignAndAuth,
8486+ OptionHandler (PointerAuthenticationMode::SignAndAuth,
8487+ &AuthenticationMode, &LastAuthenticationMode))
8488+ .Default ([&](StringRef Option) {
8489+ if (size_t WhitespaceIndex =
8490+ Option.find_first_of (" \t\n\v\f\r " );
8491+ WhitespaceIndex != Option.npos ) {
8492+ StringRef LeadingOption = Option.slice (0 , WhitespaceIndex);
8493+ S.Diag (AuthenticationOptionsRange.getBegin (),
8494+ diag::err_ptrauth_option_missing_comma)
8495+ << AttrName << LeadingOption;
8496+ } else {
8497+ S.Diag (AuthenticationOptionsRange.getBegin (),
8498+ diag::err_ptrauth_unknown_authentication_option)
8499+ << AttrName << Option;
8500+ }
8501+ return false ;
8502+ });
8503+ if (!SelectedHandler (Option))
8504+ IsInvalid = true ;
8505+ }
83808506 }
83818507
83828508 if (!T->isSignableType () && !T->isDependentType ()) {
83838509 S.Diag (Attr.getLoc (), diag::err_ptrauth_qualifier_nonpointer) << T;
8510+ IsInvalid = true ;
8511+ }
8512+
8513+ if (IsInvalid) {
83848514 Attr.setInvalid ();
83858515 return ;
83868516 }
83878517
8518+ if (!AuthenticationMode)
8519+ AuthenticationMode = PointerAuthenticationMode::SignAndAuth;
8520+
83888521 if (T.getPointerAuth ()) {
83898522 S.Diag (Attr.getLoc (), diag::err_ptrauth_qualifier_redundant)
8390- << T << Attr. getAttrName ()-> getName () ;
8523+ << T << AttrName ;
83918524 Attr.setInvalid ();
83928525 return ;
83938526 }
@@ -8401,9 +8534,11 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
84018534 assert ((!IsAddressDiscriminatedArg || IsAddressDiscriminated <= 1 ) &&
84028535 " address discriminator arg should be either 0 or 1" );
84038536 PointerAuthQualifier Qual = PointerAuthQualifier::Create (
8404- Key, IsAddressDiscriminated, ExtraDiscriminator,
8405- PointerAuthenticationMode::SignAndAuth, false , false );
8537+ Key, IsAddressDiscriminated, ExtraDiscriminator, *AuthenticationMode,
8538+ IsIsaPointer, AuthenticatesNullValues);
8539+ assert (Qual.getAuthenticationMode () == *AuthenticationMode);
84068540 T = S.Context .getPointerAuthType (T, Qual);
8541+ assert (T.getPointerAuth ().getAuthenticationMode () == *AuthenticationMode);
84078542}
84088543
84098544// / HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is
0 commit comments