[clang] [clang][ptrauth] add support for options parameter to __ptrauth (PR #136828)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 23 02:00:51 PDT 2025
================
@@ -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,
----------------
ojhunt wrote:
This is more generic than is strictly needed at this point, because future PRs add additional option types and flags
https://github.com/llvm/llvm-project/pull/136828
More information about the cfe-commits
mailing list