Skip to content

Commit 8d42eca

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 bd0d048 commit 8d42eca

12 files changed

+691
-30
lines changed

clang/include/clang/Basic/Attr.td

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

35963596
def PointerAuth : TypeAttr {
35973597
let Spellings = [CustomKeyword<"__ptrauth">];
3598-
let Args = [IntArgument<"Key">,
3599-
BoolArgument<"AddressDiscriminated", 1>,
3600-
IntArgument<"ExtraDiscriminator", 1>];
3598+
let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>,
3599+
IntArgument<"ExtraDiscriminator", 1>,
3600+
StringArgument<"Options", 1>];
36013601
let Documentation = [PtrAuthDocs];
36023602
}
36033603

clang/include/clang/Basic/DiagnosticParseKinds.td

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

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

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

clang/include/clang/Basic/DiagnosticSemaKinds.td

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

1048+
// __ptrauth qualifier options string
1049+
def note_ptrauth_evaluating_options
1050+
: Note<"options parameter evaluated to '%0'">;
1051+
def err_ptrauth_invalid_option : Error<"'%0' options parameter %1">;
1052+
def err_ptrauth_unknown_authentication_option
1053+
: Error<"unknown '%0' authentication option '%1'">;
1054+
def err_ptrauth_repeated_authentication_option
1055+
: Error<"repeated '%0' authentication %select{mode|option}1%select{, prior "
1056+
"mode was '%3'| '%2'}1">;
1057+
def note_ptrauth_previous_authentication_option
1058+
: Note<"previous '%0' authentication %select{mode|option}1">;
1059+
def err_ptrauth_unexpected_option_end
1060+
: Error<"unexpected end of options parameter for %0">;
1061+
def err_ptrauth_option_unexpected_token
1062+
: Error<"unexpected character '%0' in '%1' options">;
1063+
def err_ptrauth_option_missing_comma
1064+
: Error<"missing comma after '%1' option in '%0' qualifier">;
1065+
10481066
/// main()
10491067
// static main() is not an error in C, just in C++.
10501068
def warn_static_main : Warning<"'main' should not be declared static">,
@@ -1735,7 +1753,6 @@ def err_static_assert_requirement_failed : Error<
17351753
def note_expr_evaluates_to : Note<
17361754
"expression evaluates to '%0 %1 %2'">;
17371755

1738-
17391756
def subst_user_defined_msg : TextSubstitution<
17401757
"%select{the message|the expression}0 in "
17411758
"%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
@@ -3428,7 +3428,7 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) {
34283428
T.consumeClose();
34293429
SourceLocation EndLoc = T.getCloseLocation();
34303430

3431-
if (ArgExprs.empty() || ArgExprs.size() > 3) {
3431+
if (ArgExprs.empty() || ArgExprs.size() > 4) {
34323432
Diag(KwLoc, diag::err_ptrauth_qualifier_bad_arg_count);
34333433
return;
34343434
}

clang/lib/Sema/SemaType.cpp

Lines changed: 148 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8350,14 +8350,16 @@ 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");
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)) {
@@ -8373,10 +8375,138 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83738375
IsAddressDiscriminated);
83748376
IsInvalid |= !S.checkPointerAuthDiscriminatorArg(
83758377
ExtraDiscriminatorArg, PointerAuthDiscArgKind::Extra, ExtraDiscriminator);
8378+
std::string LastAuthenticationMode;
8379+
std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt;
8380+
bool IsIsaPointer = false;
8381+
bool AuthenticatesNullValues = false;
8382+
8383+
if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors()) {
8384+
StringRef OptionsString;
8385+
std::string EvaluatedString;
8386+
bool HasEvaluatedOptionsString = false;
8387+
const StringLiteral *OptionsStringLiteral =
8388+
dyn_cast<StringLiteral>(AuthenticationOptionsArg);
8389+
SourceRange AuthenticationOptionsRange =
8390+
AuthenticationOptionsArg->getSourceRange();
8391+
bool ReportedEvaluation = false;
8392+
auto ReportEvaluationOfExpressionIfNeeded = [&]() {
8393+
if (OptionsStringLiteral || !HasEvaluatedOptionsString ||
8394+
ReportedEvaluation)
8395+
return;
8396+
ReportedEvaluation = true;
8397+
S.Diag(AuthenticationOptionsRange.getBegin(),
8398+
diag::note_ptrauth_evaluating_options)
8399+
<< OptionsString << AuthenticationOptionsRange;
8400+
};
8401+
auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason) {
8402+
S.Diag(AuthenticationOptionsRange.getBegin(),
8403+
diag::err_ptrauth_invalid_option)
8404+
<< AttrName << Reason;
8405+
Attr.setInvalid();
8406+
IsInvalid = true;
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+
.Case(PointerAuthenticationOptionIsaPointer,
8489+
OptionHandler(true, &IsIsaPointer))
8490+
.Case(PointerAuthenticationOptionAuthenticatesNullValues,
8491+
OptionHandler(true, &AuthenticatesNullValues))
8492+
.Default([&](StringRef Option) {
8493+
if (size_t WhitespaceIndex =
8494+
Option.find_first_of(" \t\n\v\f\r");
8495+
WhitespaceIndex != Option.npos) {
8496+
StringRef LeadingOption = Option.slice(0, WhitespaceIndex);
8497+
S.Diag(AuthenticationOptionsRange.getBegin(),
8498+
diag::err_ptrauth_option_missing_comma)
8499+
<< AttrName << LeadingOption;
8500+
} else {
8501+
S.Diag(AuthenticationOptionsRange.getBegin(),
8502+
diag::err_ptrauth_unknown_authentication_option)
8503+
<< AttrName << Option;
8504+
}
8505+
return false;
8506+
});
8507+
if (!SelectedHandler(Option))
8508+
IsInvalid = true;
8509+
}
83808510
}
83818511

83828512
if (!T->isSignableType(Ctx) && !T->isDependentType()) {
@@ -8385,6 +8515,9 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
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) << T;
83908523
Attr.setInvalid();
@@ -8397,13 +8530,19 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
83978530
return;
83988531
}
83998532

8533+
if (IsInvalid) {
8534+
Attr.setInvalid();
8535+
return;
8536+
}
8537+
84008538
assert((!IsAddressDiscriminatedArg || IsAddressDiscriminated <= 1) &&
84018539
"address discriminator arg should be either 0 or 1");
84028540
PointerAuthQualifier Qual = PointerAuthQualifier::Create(
8403-
Key, IsAddressDiscriminated, ExtraDiscriminator,
8404-
PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false,
8405-
/*AuthenticatesNullValues=*/false);
8541+
Key, IsAddressDiscriminated, ExtraDiscriminator, *AuthenticationMode,
8542+
IsIsaPointer, AuthenticatesNullValues);
8543+
assert(Qual.getAuthenticationMode() == *AuthenticationMode);
84068544
T = S.Context.getPointerAuthType(T, Qual);
8545+
assert(T.getPointerAuth().getAuthenticationMode() == *AuthenticationMode);
84078546
}
84088547

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

0 commit comments

Comments
 (0)