Skip to content

Commit 927380b

Browse files
committed
[clang][PAC] 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" We also support parsing the options but not yet the implementation * "isa-pointer" * "authenticates-null-values" 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.
1 parent 6212c19 commit 927380b

12 files changed

+683
-30
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3606,9 +3606,9 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
36063606

36073607
def PointerAuth : TypeAttr {
36083608
let Spellings = [CustomKeyword<"__ptrauth">];
3609-
let Args = [IntArgument<"Key">,
3610-
BoolArgument<"AddressDiscriminated", 1>,
3611-
IntArgument<"ExtraDiscriminator", 1>];
3609+
let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>,
3610+
IntArgument<"ExtraDiscriminator", 1>,
3611+
StringArgument<"Options", 1>];
36123612
let Documentation = [PtrAuthDocs];
36133613
}
36143614

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,8 +1736,8 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning<
17361736
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
17371737
InGroup<CudaCompat>;
17381738

1739-
def err_ptrauth_qualifier_bad_arg_count : Error<
1740-
"'__ptrauth' qualifier must take between 1 and 3 arguments">;
1739+
def err_ptrauth_qualifier_bad_arg_count
1740+
: Error<"'__ptrauth' qualifier must take between 1 and 4 arguments">;
17411741

17421742
def warn_cuda_attr_lambda_position : Warning<
17431743
"nvcc does not allow '__%0__' to appear after the parameter list in lambdas">,

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,18 @@ def err_ptrauth_extra_discriminator_invalid : Error<
10471047
"invalid extra discriminator flag '%0'; '__ptrauth' requires a value between "
10481048
"'0' and '%1'">;
10491049

1050+
// __ptrauth qualifier options string
1051+
def note_ptrauth_evaluating_options
1052+
: Note<"options parameter evaluated to '%0'">;
1053+
def err_ptrauth_invalid_option : Error<"'__ptrauth' options parameter %0">;
1054+
def err_ptrauth_unknown_authentication_option
1055+
: Error<"unknown '__ptrauth' authentication option '%0'">;
1056+
def err_ptrauth_repeated_authentication_option
1057+
: Error<"repeated '__ptrauth' authentication %select{mode|option}0%select{, prior "
1058+
"mode was '%2'| '%1'}0">;
1059+
def err_ptrauth_option_missing_comma
1060+
: Error<"missing comma after '%0' option in '__ptrauth' qualifier">;
1061+
10501062
/// main()
10511063
// static main() is not an error in C, just in C++.
10521064
def warn_static_main : Warning<"'main' should not be declared static">,
@@ -1737,7 +1749,6 @@ def err_static_assert_requirement_failed : Error<
17371749
def note_expr_evaluates_to : Note<
17381750
"expression evaluates to '%0 %1 %2'">;
17391751

1740-
17411752
def subst_user_defined_msg : TextSubstitution<
17421753
"%select{the message|the expression}0 in "
17431754
"%select{a static assertion|this asm operand}0">;

clang/include/clang/Basic/LangOptions.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ enum class PointerAuthenticationMode : unsigned {
6565
SignAndAuth
6666
};
6767

68+
static constexpr llvm::StringLiteral PointerAuthenticationOptionStrip = "strip";
69+
static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndStrip =
70+
"sign-and-strip";
71+
static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndAuth =
72+
"sign-and-auth";
73+
static constexpr llvm::StringLiteral PointerAuthenticationOptionIsaPointer =
74+
"isa-pointer";
75+
static constexpr llvm::StringLiteral
76+
PointerAuthenticationOptionAuthenticatesNullValues =
77+
"authenticates-null-values";
78+
6879
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
6980
/// this large collection of bitfields is a trivial class type.
7081
class LangOptionsBase {

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,13 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
21292129

21302130
}
21312131

2132+
static bool shouldSignPointer(const PointerAuthQualifier &PointerAuth) {
2133+
PointerAuthenticationMode AuthenticationMode =
2134+
PointerAuth.getAuthenticationMode();
2135+
return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
2136+
AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
2137+
}
2138+
21322139
llvm::Constant *ConstantLValueEmitter::tryEmit() {
21332140
const APValue::LValueBase &base = Value.getLValueBase();
21342141

@@ -2162,7 +2169,8 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() {
21622169

21632170
// Apply pointer-auth signing from the destination type.
21642171
if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
2165-
PointerAuth && !result.HasDestPointerAuth) {
2172+
PointerAuth && !result.HasDestPointerAuth &&
2173+
shouldSignPointer(PointerAuth)) {
21662174
value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth);
21672175
if (!value)
21682176
return nullptr;
@@ -2210,16 +2218,17 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
22102218
if (D->hasAttr<WeakRefAttr>())
22112219
return CGM.GetWeakRefReference(D).getPointer();
22122220

2213-
auto PtrAuthSign = [&](llvm::Constant *C) {
2214-
if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth()) {
2221+
auto PtrAuthSign = [&](llvm::Constant *C, bool IsFunction) {
2222+
if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
2223+
PointerAuth && shouldSignPointer(PointerAuth)) {
22152224
C = applyOffset(C);
22162225
C = Emitter.tryEmitConstantSignedPointer(C, PointerAuth);
22172226
return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true);
22182227
}
22192228

22202229
CGPointerAuthInfo AuthInfo;
22212230

2222-
if (EnablePtrAuthFunctionTypeDiscrimination)
2231+
if (IsFunction && EnablePtrAuthFunctionTypeDiscrimination)
22232232
AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
22242233

22252234
if (AuthInfo) {
@@ -2237,17 +2246,18 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
22372246
};
22382247

22392248
if (const auto *FD = dyn_cast<FunctionDecl>(D))
2240-
return PtrAuthSign(CGM.getRawFunctionPointer(FD));
2249+
return PtrAuthSign(CGM.getRawFunctionPointer(FD), /*IsFunction=*/true);
22412250

22422251
if (const auto *VD = dyn_cast<VarDecl>(D)) {
22432252
// We can never refer to a variable with local storage.
22442253
if (!VD->hasLocalStorage()) {
22452254
if (VD->isFileVarDecl() || VD->hasExternalStorage())
2246-
return CGM.GetAddrOfGlobalVar(VD);
2255+
return PtrAuthSign(CGM.GetAddrOfGlobalVar(VD), /*IsFunction=*/false);
22472256

22482257
if (VD->isLocalVarDecl()) {
2249-
return CGM.getOrCreateStaticVarDecl(
2258+
llvm::Constant *C = CGM.getOrCreateStaticVarDecl(
22502259
*VD, CGM.getLLVMLinkageVarDefinition(VD));
2260+
return PtrAuthSign(C, /*IsFunction=*/false);
22512261
}
22522262
}
22532263
}

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3176,7 +3176,7 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) {
31763176
T.consumeClose();
31773177
SourceLocation EndLoc = T.getCloseLocation();
31783178

3179-
if (ArgExprs.empty() || ArgExprs.size() > 3) {
3179+
if (ArgExprs.empty() || ArgExprs.size() > 4) {
31803180
Diag(KwLoc, diag::err_ptrauth_qualifier_bad_arg_count);
31813181
return;
31823182
}

clang/lib/Sema/SemaType.cpp

Lines changed: 146 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8350,14 +8350,15 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
83508350
/// Handle the __ptrauth qualifier.
83518351
static 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");
83568355
Expr *KeyArg = Attr.getArgAsExpr(0);
83578356
Expr *IsAddressDiscriminatedArg =
83588357
Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr;
83598358
Expr *ExtraDiscriminatorArg =
83608359
Attr.getNumArgs() >= 3 ? Attr.getArgAsExpr(2) : nullptr;
8360+
Expr *AuthenticationOptionsArg =
8361+
Attr.getNumArgs() >= 4 ? Attr.getArgAsExpr(3) : nullptr;
83618362

83628363
unsigned Key;
83638364
if (S.checkConstantPointerAuthKey(KeyArg, Key)) {
@@ -8373,10 +8374,137 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83738374
IsAddressDiscriminated);
83748375
IsInvalid |= !S.checkPointerAuthDiscriminatorArg(
83758376
ExtraDiscriminatorArg, PointerAuthDiscArgKind::Extra, ExtraDiscriminator);
8377+
std::string LastAuthenticationMode;
8378+
std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt;
8379+
bool IsIsaPointer = false;
8380+
bool AuthenticatesNullValues = false;
8381+
8382+
if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors()) {
8383+
StringRef OptionsString;
8384+
std::string EvaluatedString;
8385+
bool HasEvaluatedOptionsString = false;
8386+
const StringLiteral *OptionsStringLiteral =
8387+
dyn_cast<StringLiteral>(AuthenticationOptionsArg);
8388+
SourceRange AuthenticationOptionsRange =
8389+
AuthenticationOptionsArg->getSourceRange();
8390+
bool ReportedEvaluation = false;
8391+
auto ReportEvaluationOfExpressionIfNeeded = [&]() {
8392+
if (OptionsStringLiteral || !HasEvaluatedOptionsString ||
8393+
ReportedEvaluation)
8394+
return;
8395+
ReportedEvaluation = true;
8396+
S.Diag(AuthenticationOptionsRange.getBegin(),
8397+
diag::note_ptrauth_evaluating_options)
8398+
<< OptionsString << AuthenticationOptionsRange;
8399+
};
8400+
auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason) {
8401+
S.Diag(AuthenticationOptionsRange.getBegin(),
8402+
diag::err_ptrauth_invalid_option) << Reason;
8403+
Attr.setInvalid();
8404+
IsInvalid = true;
8405+
ReportEvaluationOfExpressionIfNeeded();
8406+
};
8407+
if (AuthenticationOptionsArg->isValueDependent() ||
8408+
AuthenticationOptionsArg->isTypeDependent()) {
8409+
DiagnoseInvalidOptionsParameter("is dependent");
8410+
return;
8411+
}
8412+
if (OptionsStringLiteral) {
8413+
OptionsString = OptionsStringLiteral->getString();
8414+
HasEvaluatedOptionsString = true;
8415+
} else {
8416+
Expr::EvalResult Eval;
8417+
bool Result = AuthenticationOptionsArg->EvaluateAsRValue(Eval, Ctx);
8418+
if (Result && Eval.Val.isLValue()) {
8419+
auto *BaseExpr = Eval.Val.getLValueBase().dyn_cast<const Expr *>();
8420+
const StringLiteral *EvaluatedStringLiteral =
8421+
dyn_cast<StringLiteral>(const_cast<Expr *>(BaseExpr));
8422+
if (EvaluatedStringLiteral) {
8423+
CharUnits StartOffset = Eval.Val.getLValueOffset();
8424+
EvaluatedString = EvaluatedStringLiteral->getString().drop_front(
8425+
StartOffset.getQuantity());
8426+
OptionsString = EvaluatedString;
8427+
HasEvaluatedOptionsString = true;
8428+
}
8429+
}
8430+
}
8431+
if (!HasEvaluatedOptionsString) {
8432+
DiagnoseInvalidOptionsParameter(
8433+
"must be a string of comma separated flags");
8434+
return;
8435+
}
8436+
for (char Ch : OptionsString) {
8437+
if (Ch != '-' && Ch != ',' && !isWhitespace(Ch) && !isalpha(Ch)) {
8438+
DiagnoseInvalidOptionsParameter("contains invalid characters");
8439+
return;
8440+
}
8441+
}
8442+
HasEvaluatedOptionsString = true;
8443+
OptionsString = OptionsString.trim();
8444+
llvm::SmallVector<StringRef> Options;
8445+
if (!OptionsString.empty())
8446+
OptionsString.split(Options, ',');
8447+
8448+
auto OptionHandler = [&](auto Value, auto *Option,
8449+
std::string *LastOption = nullptr) {
8450+
return [&, Value, Option, LastOption](StringRef OptionString) {
8451+
if (!*Option) {
8452+
*Option = Value;
8453+
if (LastOption)
8454+
*LastOption = OptionString;
8455+
return true;
8456+
}
8457+
bool IsAuthenticationMode =
8458+
std::is_same_v<decltype(Value), PointerAuthenticationMode>;
8459+
S.Diag(AuthenticationOptionsRange.getBegin(),
8460+
diag::err_ptrauth_repeated_authentication_option)
8461+
<< !IsAuthenticationMode << OptionString
8462+
<< (LastOption ? *LastOption : "");
8463+
return false;
8464+
};
8465+
};
83768466

8377-
if (IsInvalid) {
8378-
Attr.setInvalid();
8379-
return;
8467+
for (unsigned Idx = 0; Idx < Options.size(); ++Idx) {
8468+
StringRef Option = Options[Idx].trim();
8469+
if (Option.empty()) {
8470+
bool IsLastOption = Idx == (Options.size() - 1);
8471+
DiagnoseInvalidOptionsParameter(
8472+
IsLastOption ? "has a trailing comma" : "contains an empty option");
8473+
continue;
8474+
}
8475+
auto SelectedHandler =
8476+
llvm::StringSwitch<std::function<bool(StringRef)>>(Option)
8477+
.Case(PointerAuthenticationOptionStrip,
8478+
OptionHandler(PointerAuthenticationMode::Strip,
8479+
&AuthenticationMode, &LastAuthenticationMode))
8480+
.Case(PointerAuthenticationOptionSignAndStrip,
8481+
OptionHandler(PointerAuthenticationMode::SignAndStrip,
8482+
&AuthenticationMode, &LastAuthenticationMode))
8483+
.Case(PointerAuthenticationOptionSignAndAuth,
8484+
OptionHandler(PointerAuthenticationMode::SignAndAuth,
8485+
&AuthenticationMode, &LastAuthenticationMode))
8486+
.Case(PointerAuthenticationOptionIsaPointer,
8487+
OptionHandler(true, &IsIsaPointer))
8488+
.Case(PointerAuthenticationOptionAuthenticatesNullValues,
8489+
OptionHandler(true, &AuthenticatesNullValues))
8490+
.Default([&](StringRef Option) {
8491+
if (size_t WhitespaceIndex =
8492+
Option.find_first_of(" \t\n\v\f\r");
8493+
WhitespaceIndex != Option.npos) {
8494+
StringRef LeadingOption = Option.slice(0, WhitespaceIndex);
8495+
S.Diag(AuthenticationOptionsRange.getBegin(),
8496+
diag::err_ptrauth_option_missing_comma)
8497+
<< LeadingOption;
8498+
} else {
8499+
S.Diag(AuthenticationOptionsRange.getBegin(),
8500+
diag::err_ptrauth_unknown_authentication_option)
8501+
<< Option;
8502+
}
8503+
return false;
8504+
});
8505+
if (!SelectedHandler(Option))
8506+
IsInvalid = true;
8507+
}
83808508
}
83818509

83828510
if (!T->isSignableType(Ctx) && !T->isDependentType()) {
@@ -8385,6 +8513,9 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83858513
return;
83868514
}
83878515

8516+
if (!AuthenticationMode)
8517+
AuthenticationMode = PointerAuthenticationMode::SignAndAuth;
8518+
83888519
if (T.getPointerAuth()) {
83898520
S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) << T;
83908521
Attr.setInvalid();
@@ -8397,13 +8528,19 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83978528
return;
83988529
}
83998530

8531+
if (IsInvalid) {
8532+
Attr.setInvalid();
8533+
return;
8534+
}
8535+
84008536
assert((!IsAddressDiscriminatedArg || IsAddressDiscriminated <= 1) &&
84018537
"address discriminator arg should be either 0 or 1");
84028538
PointerAuthQualifier Qual = PointerAuthQualifier::Create(
8403-
Key, IsAddressDiscriminated, ExtraDiscriminator,
8404-
PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false,
8405-
/*AuthenticatesNullValues=*/false);
8539+
Key, IsAddressDiscriminated, ExtraDiscriminator, *AuthenticationMode,
8540+
IsIsaPointer, AuthenticatesNullValues);
8541+
assert(Qual.getAuthenticationMode() == *AuthenticationMode);
84068542
T = S.Context.getPointerAuthType(T, Qual);
8543+
assert(T.getPointerAuth().getAuthenticationMode() == *AuthenticationMode);
84078544
}
84088545

84098546
/// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is

0 commit comments

Comments
 (0)