forked from OSchip/llvm-project
Adding nocf_check attribute for cf-protection fine tuning
The patch adds nocf_check target independent attribute for disabling checks that were enabled by cf-protection flag. The attribute can be appertained to functions and function pointers. Attribute name follows GCC's similar attribute name. Differential Revision: https://reviews.llvm.org/D41880 llvm-svn: 327768
This commit is contained in:
parent
fdd72fd522
commit
220671a080
|
@ -1511,7 +1511,7 @@ protected:
|
|||
|
||||
/// Extra information which affects how the function is called, like
|
||||
/// regparm and the calling convention.
|
||||
unsigned ExtInfo : 11;
|
||||
unsigned ExtInfo : 12;
|
||||
|
||||
/// Used only by FunctionProtoType, put here to pack with the
|
||||
/// other bitfields.
|
||||
|
@ -3147,24 +3147,24 @@ public:
|
|||
class ExtInfo {
|
||||
friend class FunctionType;
|
||||
|
||||
// Feel free to rearrange or add bits, but if you go over 11,
|
||||
// Feel free to rearrange or add bits, but if you go over 12,
|
||||
// you'll need to adjust both the Bits field below and
|
||||
// Type::FunctionTypeBitfields.
|
||||
|
||||
// | CC |noreturn|produces|nocallersavedregs|regparm|
|
||||
// |0 .. 4| 5 | 6 | 7 |8 .. 10|
|
||||
// | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|
|
||||
// |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 |
|
||||
//
|
||||
// regparm is either 0 (no regparm attribute) or the regparm value+1.
|
||||
enum { CallConvMask = 0x1F };
|
||||
enum { NoReturnMask = 0x20 };
|
||||
enum { ProducesResultMask = 0x40 };
|
||||
enum { NoCallerSavedRegsMask = 0x80 };
|
||||
enum { NoCfCheckMask = 0x800 };
|
||||
enum {
|
||||
RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask |
|
||||
NoCallerSavedRegsMask),
|
||||
NoCallerSavedRegsMask | NoCfCheckMask),
|
||||
RegParmOffset = 8
|
||||
}; // Assumed to be the last field
|
||||
|
||||
uint16_t Bits = CC_C;
|
||||
|
||||
ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {}
|
||||
|
@ -3173,12 +3173,13 @@ public:
|
|||
// Constructor with no defaults. Use this when you know that you
|
||||
// have all the elements (when reading an AST file for example).
|
||||
ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
|
||||
bool producesResult, bool noCallerSavedRegs) {
|
||||
bool producesResult, bool noCallerSavedRegs, bool NoCfCheck) {
|
||||
assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
|
||||
Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
|
||||
(producesResult ? ProducesResultMask : 0) |
|
||||
(noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
|
||||
(hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
|
||||
(hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) |
|
||||
(NoCfCheck ? NoCfCheckMask : 0);
|
||||
}
|
||||
|
||||
// Constructor with all defaults. Use when for example creating a
|
||||
|
@ -3192,10 +3193,11 @@ public:
|
|||
bool getNoReturn() const { return Bits & NoReturnMask; }
|
||||
bool getProducesResult() const { return Bits & ProducesResultMask; }
|
||||
bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
|
||||
bool getNoCfCheck() const { return Bits & NoCfCheckMask; }
|
||||
bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; }
|
||||
|
||||
unsigned getRegParm() const {
|
||||
unsigned RegParm = Bits >> RegParmOffset;
|
||||
unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset;
|
||||
if (RegParm > 0)
|
||||
--RegParm;
|
||||
return RegParm;
|
||||
|
@ -3234,6 +3236,13 @@ public:
|
|||
return ExtInfo(Bits & ~NoCallerSavedRegsMask);
|
||||
}
|
||||
|
||||
ExtInfo withNoCfCheck(bool noCfCheck) const {
|
||||
if (noCfCheck)
|
||||
return ExtInfo(Bits | NoCfCheckMask);
|
||||
else
|
||||
return ExtInfo(Bits & ~NoCfCheckMask);
|
||||
}
|
||||
|
||||
ExtInfo withRegParm(unsigned RegParm) const {
|
||||
assert(RegParm < 7 && "Invalid regparm value");
|
||||
return ExtInfo((Bits & ~RegParmMask) |
|
||||
|
@ -4120,6 +4129,7 @@ public:
|
|||
|
||||
// No operand.
|
||||
attr_noreturn,
|
||||
attr_nocf_check,
|
||||
attr_cdecl,
|
||||
attr_fastcall,
|
||||
attr_stdcall,
|
||||
|
|
|
@ -2122,6 +2122,12 @@ def AnyX86NoCallerSavedRegisters : InheritableAttr,
|
|||
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
|
||||
}
|
||||
|
||||
def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{
|
||||
let Spellings = [GCC<"nocf_check">];
|
||||
let Subjects = SubjectList<[FunctionLike]>;
|
||||
let Documentation = [AnyX86NoCfCheckDocs];
|
||||
}
|
||||
|
||||
def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
|
||||
let Spellings = [GCC<"force_align_arg_pointer">];
|
||||
// Technically, this appertains to a FunctionDecl, but the target-specific
|
||||
|
|
|
@ -2913,6 +2913,24 @@ jumps from i386 arch code).
|
|||
}];
|
||||
}
|
||||
|
||||
def AnyX86NoCfCheckDocs : Documentation{
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Jump Oriented Programming attacks rely on tampering with addresses used by
|
||||
indirect call / jmp, e.g. redirect control-flow to non-programmer
|
||||
intended bytes in the binary.
|
||||
X86 Supports Indirect Branch Tracking (IBT) as part of Control-Flow
|
||||
Enforcement Technology (CET). IBT instruments ENDBR instructions used to
|
||||
specify valid targets of indirect call / jmp.
|
||||
The ``nocf_check`` attribute has two roles:
|
||||
1. Appertains to a function - do not add ENDBR instruction at the
|
||||
beginning of the function.
|
||||
2. Appertains to a function pointer - do not track the target
|
||||
function of this pointer (by adding nocf_check prefix to the
|
||||
indirect-call instruction).
|
||||
}];
|
||||
}
|
||||
|
||||
def SwiftCallDocs : Documentation {
|
||||
let Category = DocCatVariable;
|
||||
let Content = [{
|
||||
|
|
|
@ -2691,6 +2691,9 @@ def warn_attribute_ignored : Warning<"%0 attribute ignored">,
|
|||
def warn_attribute_ignored_on_inline :
|
||||
Warning<"%0 attribute ignored on inline function">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_nocf_check_attribute_ignored :
|
||||
Warning<"'nocf_check' attribute ignored; use -fcf-protection to enable the attribute">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_after_definition_ignored : Warning<
|
||||
"attribute %0 after definition is ignored">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
|
|
|
@ -236,6 +236,7 @@ LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
|
|||
LANGOPT(ObjCWeakRuntime , 1, 0, "__weak support in the ARC runtime")
|
||||
LANGOPT(ObjCWeak , 1, 0, "Objective-C __weak in ARC and MRC files")
|
||||
LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in legacy ObjectiveC runtime")
|
||||
LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
|
||||
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
|
||||
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
|
||||
LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL")
|
||||
|
|
|
@ -494,7 +494,7 @@ class CGFunctionInfo final
|
|||
unsigned EffectiveCallingConvention : 8;
|
||||
|
||||
/// The clang::CallingConv that this was originally created with.
|
||||
unsigned ASTCallingConvention : 7;
|
||||
unsigned ASTCallingConvention : 6;
|
||||
|
||||
/// Whether this is an instance method.
|
||||
unsigned InstanceMethod : 1;
|
||||
|
@ -515,6 +515,9 @@ class CGFunctionInfo final
|
|||
unsigned HasRegParm : 1;
|
||||
unsigned RegParm : 3;
|
||||
|
||||
/// Whether this function has nocf_check attribute.
|
||||
unsigned NoCfCheck : 1;
|
||||
|
||||
RequiredArgs Required;
|
||||
|
||||
/// The struct representing all arguments passed in memory. Only used when
|
||||
|
@ -599,6 +602,9 @@ public:
|
|||
/// Whether this function no longer saves caller registers.
|
||||
bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; }
|
||||
|
||||
/// Whether this function has nocf_check attribute.
|
||||
bool isNoCfCheck() const { return NoCfCheck; }
|
||||
|
||||
/// getASTCallingConvention() - Return the AST-specified calling
|
||||
/// convention.
|
||||
CallingConv getASTCallingConvention() const {
|
||||
|
@ -624,7 +630,7 @@ public:
|
|||
FunctionType::ExtInfo getExtInfo() const {
|
||||
return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(),
|
||||
getASTCallingConvention(), isReturnsRetained(),
|
||||
isNoCallerSavedRegs());
|
||||
isNoCallerSavedRegs(), isNoCfCheck());
|
||||
}
|
||||
|
||||
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
|
||||
|
@ -664,6 +670,7 @@ public:
|
|||
ID.AddBoolean(NoCallerSavedRegs);
|
||||
ID.AddBoolean(HasRegParm);
|
||||
ID.AddInteger(RegParm);
|
||||
ID.AddBoolean(NoCfCheck);
|
||||
ID.AddInteger(Required.getOpaqueData());
|
||||
ID.AddBoolean(HasExtParameterInfos);
|
||||
if (HasExtParameterInfos) {
|
||||
|
@ -690,6 +697,7 @@ public:
|
|||
ID.AddBoolean(info.getNoCallerSavedRegs());
|
||||
ID.AddBoolean(info.getHasRegParm());
|
||||
ID.AddInteger(info.getRegParm());
|
||||
ID.AddBoolean(info.getNoCfCheck());
|
||||
ID.AddInteger(required.getOpaqueData());
|
||||
ID.AddBoolean(!paramInfos.empty());
|
||||
if (!paramInfos.empty()) {
|
||||
|
|
|
@ -3323,8 +3323,8 @@ public:
|
|||
bool CheckRegparmAttr(const AttributeList &attr, unsigned &value);
|
||||
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
|
||||
const FunctionDecl *FD = nullptr);
|
||||
bool CheckNoReturnAttr(const AttributeList &attr);
|
||||
bool CheckNoCallerSavedRegsAttr(const AttributeList &attr);
|
||||
bool CheckAttrTarget(const AttributeList &CurrAttr);
|
||||
bool CheckAttrNoArgs(const AttributeList &CurrAttr);
|
||||
bool checkStringLiteralArgumentAttr(const AttributeList &Attr,
|
||||
unsigned ArgNum, StringRef &Str,
|
||||
SourceLocation *ArgLocation = nullptr);
|
||||
|
|
|
@ -8241,6 +8241,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
|
|||
return QualType();
|
||||
if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs())
|
||||
return QualType();
|
||||
if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck())
|
||||
return QualType();
|
||||
|
||||
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
|
||||
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
|
||||
|
|
|
@ -3129,6 +3129,7 @@ bool AttributedType::isQualifier() const {
|
|||
case AttributedType::attr_uptr:
|
||||
case AttributedType::attr_objc_kindof:
|
||||
case AttributedType::attr_ns_returns_retained:
|
||||
case AttributedType::attr_nocf_check:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad attributed type kind");
|
||||
|
@ -3166,6 +3167,7 @@ bool AttributedType::isCallingConv() const {
|
|||
case attr_nullable:
|
||||
case attr_null_unspecified:
|
||||
case attr_objc_kindof:
|
||||
case attr_nocf_check:
|
||||
return false;
|
||||
|
||||
case attr_pcs:
|
||||
|
|
|
@ -801,6 +801,8 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
|
|||
<< Info.getRegParm() << ")))";
|
||||
if (Info.getNoCallerSavedRegs())
|
||||
OS << " __attribute__((no_caller_saved_registers))";
|
||||
if (Info.getNoCfCheck())
|
||||
OS << " __attribute__((nocf_check))";
|
||||
}
|
||||
|
||||
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
|
||||
|
@ -1396,7 +1398,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
|||
// FIXME: When Sema learns to form this AttributedType, avoid printing the
|
||||
// attribute again in printFunctionProtoAfter.
|
||||
case AttributedType::attr_noreturn: OS << "noreturn"; break;
|
||||
|
||||
case AttributedType::attr_nocf_check: OS << "nocf_check"; break;
|
||||
case AttributedType::attr_cdecl: OS << "cdecl"; break;
|
||||
case AttributedType::attr_fastcall: OS << "fastcall"; break;
|
||||
case AttributedType::attr_stdcall: OS << "stdcall"; break;
|
||||
|
|
|
@ -803,6 +803,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
|
|||
FI->NoReturn = info.getNoReturn();
|
||||
FI->ReturnsRetained = info.getProducesResult();
|
||||
FI->NoCallerSavedRegs = info.getNoCallerSavedRegs();
|
||||
FI->NoCfCheck = info.getNoCfCheck();
|
||||
FI->Required = required;
|
||||
FI->HasRegParm = info.getHasRegParm();
|
||||
FI->RegParm = info.getRegParm();
|
||||
|
@ -1850,6 +1851,8 @@ void CodeGenModule::ConstructAttributeList(
|
|||
RetAttrs.addAttribute(llvm::Attribute::NonNull);
|
||||
if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
|
||||
FuncAttrs.addAttribute("no_caller_saved_registers");
|
||||
if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>())
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck);
|
||||
|
||||
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
|
||||
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
|
||||
|
|
|
@ -2042,6 +2042,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
}
|
||||
}
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
|
||||
StringRef Name = A->getValue();
|
||||
if (Name == "full" || Name == "branch") {
|
||||
Opts.CFProtectionBranch = 1;
|
||||
}
|
||||
}
|
||||
// -cl-std only applies for OpenCL language standards.
|
||||
// Override the -std option in this case.
|
||||
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
|
||||
|
|
|
@ -1908,9 +1908,6 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
|||
static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
|
||||
if (hasDeclarator(D)) return;
|
||||
|
||||
if (S.CheckNoReturnAttr(Attrs))
|
||||
return;
|
||||
|
||||
if (!isa<ObjCMethodDecl>(D)) {
|
||||
S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< Attrs.getName() << ExpectedFunctionOrMethod;
|
||||
|
@ -1921,16 +1918,14 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
|
|||
Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
|
||||
const AttributeList &AL) {
|
||||
if (S.CheckNoCallerSavedRegsAttr(AL))
|
||||
return;
|
||||
|
||||
D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr(
|
||||
AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
|
||||
static void handleNoCfCheckAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
|
||||
if (!S.getLangOpts().CFProtectionBranch)
|
||||
S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored);
|
||||
else
|
||||
handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs);
|
||||
}
|
||||
|
||||
bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) {
|
||||
bool Sema::CheckAttrNoArgs(const AttributeList &Attrs) {
|
||||
if (!checkAttributeNumArgs(*this, Attrs, 0)) {
|
||||
Attrs.setInvalid();
|
||||
return true;
|
||||
|
@ -1939,7 +1934,7 @@ bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &AL) {
|
||||
bool Sema::CheckAttrTarget(const AttributeList &AL) {
|
||||
// Check whether the attribute is valid on the current target.
|
||||
if (!AL.existsInTarget(Context.getTargetInfo())) {
|
||||
Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName();
|
||||
|
@ -1947,11 +1942,6 @@ bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &AL) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!checkAttributeNumArgs(*this, AL, 0)) {
|
||||
AL.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5756,6 +5746,9 @@ static bool handleCommonAttributeFeatures(Sema &S, Decl *D,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (S.CheckAttrTarget(AL))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6052,6 +6045,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case AttributeList::AT_NoReturn:
|
||||
handleNoReturnAttr(S, D, AL);
|
||||
break;
|
||||
case AttributeList::AT_AnyX86NoCfCheck:
|
||||
handleNoCfCheckAttr(S, D, AL);
|
||||
break;
|
||||
case AttributeList::AT_NoThrow:
|
||||
handleSimpleAttribute<NoThrowAttr>(S, D, AL);
|
||||
break;
|
||||
|
@ -6427,7 +6423,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
handleTypeTagForDatatypeAttr(S, D, AL);
|
||||
break;
|
||||
case AttributeList::AT_AnyX86NoCallerSavedRegisters:
|
||||
handleNoCallerSavedRegsAttr(S, D, AL);
|
||||
handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL);
|
||||
break;
|
||||
case AttributeList::AT_RenderScriptKernel:
|
||||
handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL);
|
||||
|
|
|
@ -125,6 +125,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
|
|||
case AttributeList::AT_NoReturn: \
|
||||
case AttributeList::AT_Regparm: \
|
||||
case AttributeList::AT_AnyX86NoCallerSavedRegisters: \
|
||||
case AttributeList::AT_AnyX86NoCfCheck: \
|
||||
CALLING_CONV_ATTRS_CASELIST
|
||||
|
||||
// Microsoft-specific type qualifiers.
|
||||
|
@ -5144,6 +5145,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
|
|||
return AttributeList::AT_ObjCOwnership;
|
||||
case AttributedType::attr_noreturn:
|
||||
return AttributeList::AT_NoReturn;
|
||||
case AttributedType::attr_nocf_check:
|
||||
return AttributeList::AT_AnyX86NoCfCheck;
|
||||
case AttributedType::attr_cdecl:
|
||||
return AttributeList::AT_CDecl;
|
||||
case AttributedType::attr_fastcall:
|
||||
|
@ -6609,7 +6612,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
|
|||
FunctionTypeUnwrapper unwrapped(S, type);
|
||||
|
||||
if (attr.getKind() == AttributeList::AT_NoReturn) {
|
||||
if (S.CheckNoReturnAttr(attr))
|
||||
if (S.CheckAttrNoArgs(attr))
|
||||
return true;
|
||||
|
||||
// Delay if this is not a function type.
|
||||
|
@ -6649,7 +6652,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
|
|||
}
|
||||
|
||||
if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) {
|
||||
if (S.CheckNoCallerSavedRegsAttr(attr))
|
||||
if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr))
|
||||
return true;
|
||||
|
||||
// Delay if this is not a function type.
|
||||
|
@ -6662,6 +6665,27 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (attr.getKind() == AttributeList::AT_AnyX86NoCfCheck) {
|
||||
if (!S.getLangOpts().CFProtectionBranch) {
|
||||
S.Diag(attr.getLoc(), diag::warn_nocf_check_attribute_ignored);
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr))
|
||||
return true;
|
||||
|
||||
// If this is not a function type, warning will be asserted by subject
|
||||
// check.
|
||||
if (!unwrapped.isFunctionType())
|
||||
return true;
|
||||
|
||||
FunctionType::ExtInfo EI =
|
||||
unwrapped.get()->getExtInfo().withNoCfCheck(true);
|
||||
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attr.getKind() == AttributeList::AT_Regparm) {
|
||||
unsigned value;
|
||||
if (S.CheckRegparmAttr(attr, value))
|
||||
|
|
|
@ -6005,13 +6005,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
|||
}
|
||||
|
||||
case TYPE_FUNCTION_NO_PROTO: {
|
||||
if (Record.size() != 7) {
|
||||
if (Record.size() != 8) {
|
||||
Error("incorrect encoding of no-proto function type");
|
||||
return QualType();
|
||||
}
|
||||
QualType ResultType = readType(*Loc.F, Record, Idx);
|
||||
FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
|
||||
(CallingConv)Record[4], Record[5], Record[6]);
|
||||
(CallingConv)Record[4], Record[5], Record[6],
|
||||
Record[7]);
|
||||
return Context.getFunctionNoProtoType(ResultType, Info);
|
||||
}
|
||||
|
||||
|
@ -6024,9 +6025,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
|||
/*regparm*/ Record[3],
|
||||
static_cast<CallingConv>(Record[4]),
|
||||
/*produces*/ Record[5],
|
||||
/*nocallersavedregs*/ Record[6]);
|
||||
/*nocallersavedregs*/ Record[6],
|
||||
/*nocfcheck*/ Record[7]);
|
||||
|
||||
unsigned Idx = 7;
|
||||
unsigned Idx = 8;
|
||||
|
||||
EPI.Variadic = Record[Idx++];
|
||||
EPI.HasTrailingReturn = Record[Idx++];
|
||||
|
|
|
@ -276,6 +276,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
|
|||
Record.push_back(C.getCC());
|
||||
Record.push_back(C.getProducesResult());
|
||||
Record.push_back(C.getNoCallerSavedRegs());
|
||||
Record.push_back(C.getNoCfCheck());
|
||||
|
||||
if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
|
||||
AbbrevToUse = 0;
|
||||
|
@ -884,6 +885,7 @@ void ASTWriter::WriteTypeAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // NoCfCheck
|
||||
// FunctionProtoType
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu -o %t %s
|
||||
// RUN: %clang_cc1 -emit-llvm -fcf-protection=branch -target-feature +ibt -triple i386-linux-gnu -o %t %s
|
||||
// RUN: FileCheck --input-file=%t %s
|
||||
|
||||
// CHECK: @t5 = weak global i32 2
|
||||
|
@ -97,8 +97,20 @@ void __attribute__((section(".bar"))) t22(void) {}
|
|||
|
||||
// CHECK: define void @t22() [[NUW]] section ".bar"
|
||||
|
||||
// CHECK: define void @t23() [[NOCF_CHECK_FUNC:#[0-9]+]]
|
||||
void __attribute__((nocf_check)) t23(void) {}
|
||||
|
||||
// CHECK: call void %{{[a-z0-9]+}}() [[NOCF_CHECK_CALL:#[0-9]+]]
|
||||
typedef void (*f_t)(void);
|
||||
void t24(f_t f1) {
|
||||
__attribute__((nocf_check)) f_t p = f1;
|
||||
(*p)();
|
||||
}
|
||||
|
||||
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
|
||||
// CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} }
|
||||
// CHECK: attributes [[COLDDEF]] = { cold {{.*}}}
|
||||
// CHECK: attributes [[COLDDECL]] = { cold {{.*}}}
|
||||
// CHECK: attributes [[NOCF_CHECK_FUNC]] = { nocf_check {{.*}}}
|
||||
// CHECK: attributes [[COLDSITE]] = { cold {{.*}}}
|
||||
// CHECK: attributes [[NOCF_CHECK_CALL]] = { nocf_check }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -ffreestanding %s -triple=i386-apple-darwin -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=I386 --check-prefix=CHECK
|
||||
// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=X86_64 --check-prefix=CHECK
|
||||
// RUN: %clang_cc1 -ffreestanding %s -triple=i386-unknown-unknown -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=I386 --check-prefix=CHECK
|
||||
// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=X86_64 --check-prefix=CHECK
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -o %t -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN
|
||||
// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -o %t -triple i386-unknown-unknown -fcf-protection=branch %s 2>&1 | FileCheck %s --check-prefix=BRANCH
|
||||
// RUN: not %clang_cc1 -fsyntax-only -S -o %t -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN
|
||||
// RUN: not %clang_cc1 -fsyntax-only -S -o %t -triple i386-unknown-unknown -fcf-protection=branch %s 2>&1 | FileCheck %s --check-prefix=BRANCH
|
||||
|
||||
// RETURN: error: option 'cf-protection=return' cannot be specified without '-mshstk'
|
||||
// BRANCH: error: option 'cf-protection=branch' cannot be specified without '-mibt'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// The number of supported attributes should never go down!
|
||||
|
||||
// CHECK: #pragma clang attribute supports 67 attributes:
|
||||
// CHECK: #pragma clang attribute supports 68 attributes:
|
||||
// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
|
||||
|
@ -12,6 +12,7 @@
|
|||
// CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias)
|
||||
// CHECK-NEXT: AllocSize (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: Annotate ()
|
||||
// CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType)
|
||||
// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
|
||||
// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
|
||||
// CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -verify -fcf-protection=branch -target-feature +ibt -fsyntax-only %s
|
||||
|
||||
// Function pointer definition.
|
||||
typedef void (*FuncPointerWithNoCfCheck)(void) __attribute__((nocf_check)); // no-warning
|
||||
typedef void (*FuncPointer)(void);
|
||||
|
||||
// Dont allow function declaration and definition mismatch.
|
||||
void __attribute__((nocf_check)) testNoCfCheck(); // expected-note {{previous declaration is here}}
|
||||
void testNoCfCheck(){}; // expected-error {{conflicting types for 'testNoCfCheck'}}
|
||||
|
||||
// No variable or parameter declaration
|
||||
__attribute__((nocf_check)) int i; // expected-warning {{'nocf_check' attribute only applies to function}}
|
||||
void testNoCfCheckImpl(double __attribute__((nocf_check)) i) {} // expected-warning {{'nocf_check' attribute only applies to function}}
|
||||
|
||||
// Allow attributed function pointers as well as casting between attributed
|
||||
// and non-attributed function pointers.
|
||||
void testNoCfCheckMismatch(FuncPointer f) {
|
||||
FuncPointerWithNoCfCheck fNoCfCheck = f; // expected-warning {{incompatible function pointer types}}
|
||||
(*fNoCfCheck)(); // no-warning
|
||||
}
|
||||
|
||||
// 'nocf_check' Attribute has no parameters.
|
||||
int testNoCfCheckParams() __attribute__((nocf_check(1))); // expected-error {{'nocf_check' attribute takes no arguments}}
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %clang_cc1 -triple=i386-unknown-unknown -verify -fcf-protection=branch -target-feature +ibt -std=c++11 -fsyntax-only %s
|
||||
|
||||
// Function pointer definition.
|
||||
[[gnu::nocf_check]] typedef void (*FuncPointerWithNoCfCheck)(void); // no-warning
|
||||
typedef void (*FuncPointer)(void);
|
||||
|
||||
// Dont allow function declaration and definition mismatch.
|
||||
[[gnu::nocf_check]] void testNoCfCheck(); // expected-note {{previous declaration is here}}
|
||||
void testNoCfCheck(){}; // expected-error {{conflicting types for 'testNoCfCheck'}}
|
||||
|
||||
// No variable or parameter declaration
|
||||
int [[gnu::nocf_check]] i; // expected-error {{'nocf_check' attribute cannot be applied to types}}
|
||||
void testNoCfCheckImpl(double i [[gnu::nocf_check]]) {} // expected-warning {{'nocf_check' attribute only applies to functions and function pointers}}
|
||||
|
||||
// Allow attributed function pointers as well as casting between attributed
|
||||
// and non-attributed function pointers.
|
||||
void testNoCfCheckMismatch(FuncPointer f) {
|
||||
FuncPointerWithNoCfCheck fNoCfCheck = f; // expected-error {{cannot initialize a variable of type}}
|
||||
(*fNoCfCheck)(); // no-warning
|
||||
}
|
||||
|
||||
// 'nocf_check' Attribute has no parameters.
|
||||
[[gnu::nocf_check(1)]] int testNoCfCheckParams(); // expected-error {{'nocf_check' attribute takes no arguments}}
|
|
@ -0,0 +1,5 @@
|
|||
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -fsyntax-only -verify -fcf-protection=branch %s
|
||||
// RUN: %clang_cc1 -triple arm-unknown-linux-gnu -fsyntax-only -verify -fcf-protection=branch %s
|
||||
// RUN: %clang_cc1 -triple arm-unknown-linux-gnu -fsyntax-only -verify %s
|
||||
|
||||
void __attribute__((nocf_check)) foo(); // expected-warning-re{{{{((unknown attribute 'nocf_check' ignored)|('nocf_check' attribute ignored; use -fcf-protection to enable the attribute))}}}}
|
Loading…
Reference in New Issue