Skip to content

Commit d51ed1b

Browse files
committed
[clang][ptrauth] 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" There are other options that will be added in future, but for now these are the modes already representable by PointerAuthQualifier. 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 79210fe commit d51ed1b

12 files changed

+587
-28
lines changed

clang/include/clang/Basic/Attr.td

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

35803580
def PointerAuth : TypeAttr {
35813581
let Spellings = [CustomKeyword<"__ptrauth">];
3582-
let Args = [IntArgument<"Key">,
3583-
BoolArgument<"AddressDiscriminated", 1>,
3584-
IntArgument<"ExtraDiscriminator", 1>];
3582+
let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>,
3583+
IntArgument<"ExtraDiscriminator", 1>,
3584+
StringArgument<"Options", 1>];
35853585
let Documentation = [PtrAuthDocs];
35863586
}
35873587

clang/include/clang/Basic/DiagnosticParseKinds.td

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

1726-
def err_ptrauth_qualifier_bad_arg_count : Error<
1727-
"'__ptrauth' qualifier must take between 1 and 3 arguments">;
1726+
def err_ptrauth_qualifier_bad_arg_count
1727+
: Error<"'__ptrauth' qualifier must take between 1 and 4 arguments">;
17281728

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

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,23 @@ def err_ptrauth_address_discrimination_invalid : Error<
10401040
def err_ptrauth_extra_discriminator_invalid : Error<
10411041
"invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">;
10421042

1043+
// __ptrauth qualifier options string
1044+
def note_ptrauth_evaluating_options
1045+
: Note<"options parameter evaluated to '%0'">;
1046+
def err_ptrauth_invalid_option : Error<"'%0' options parameter %1">;
1047+
def err_ptrauth_unknown_authentication_option
1048+
: Error<"unknown '%0' authentication option '%1'">;
1049+
def err_ptrauth_repeated_authentication_option
1050+
: Error<"repeated '%0' authentication %select{mode|option}1%select{, prior mode was '%3'| '%2'}1">;
1051+
def note_ptrauth_previous_authentication_option
1052+
: Note<"previous '%0' authentication %select{mode|option}1">;
1053+
def err_ptrauth_unexpected_option_end
1054+
: Error<"unexpected end of options parameter for %0">;
1055+
def err_ptrauth_option_unexpected_token
1056+
: Error<"unexpected character '%0' in '%1' options">;
1057+
def err_ptrauth_option_missing_comma
1058+
: Error<"missing comma after '%1' option in '%0' qualifier">;
1059+
10431060
/// main()
10441061
// static main() is not an error in C, just in C++.
10451062
def warn_static_main : Warning<"'main' should not be declared static">,
@@ -1730,10 +1747,10 @@ def err_static_assert_requirement_failed : Error<
17301747
def note_expr_evaluates_to : Note<
17311748
"expression evaluates to '%0 %1 %2'">;
17321749

1733-
1734-
def subst_user_defined_msg : TextSubstitution<
1735-
"%select{the message|the expression}0 in "
1736-
"%select{a static assertion|this asm operand}0">;
1750+
def subst_user_defined_msg
1751+
: TextSubstitution<"%select{the message|the expression|the expression}0 in "
1752+
"%select{a static assertion|this asm operand|a pointer "
1753+
"authentication option}0">;
17371754

17381755
def err_user_defined_msg_invalid : Error<
17391756
"%sub{subst_user_defined_msg}0 must be a string literal or an "

clang/include/clang/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ 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+
6874
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
6975
/// this large collection of bitfields is a trivial class type.
7076
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: 144 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "llvm/IR/DerivedTypes.h"
4949
#include "llvm/Support/ErrorHandling.h"
5050
#include <bitset>
51+
#include <cctype>
5152
#include <optional>
5253

5354
using namespace clang;
@@ -8350,14 +8351,16 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
83508351
/// Handle the __ptrauth qualifier.
83518352
static 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

Comments
 (0)