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:
Oren Ben Simhon 2018-03-17 13:31:35 +00:00
parent fdd72fd522
commit 220671a080
23 changed files with 193 additions and 44 deletions

View File

@ -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,

View File

@ -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

View File

@ -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 = [{

View File

@ -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>;

View File

@ -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")

View File

@ -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()) {

View File

@ -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);

View File

@ -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();

View File

@ -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:

View File

@ -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;

View File

@ -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>()) {

View File

@ -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)) {

View File

@ -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);

View File

@ -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))

View File

@ -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++];

View File

@ -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

View File

@ -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 }

View File

@ -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>

View File

@ -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'

View File

@ -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)

View File

@ -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}}

View File

@ -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}}

View File

@ -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))}}}}