Skip to content

Commit 826ef59

Browse files
committed
[clang][slh] add Clang attr no_speculative_load_hardening
Summary: This attribute will allow users to opt specific functions out of speculative load hardening. This compliments the Clang attribute named speculative_load_hardening. When this attribute or the attribute speculative_load_hardening is used in combination with the flags -mno-speculative-load-hardening or -mspeculative-load-hardening, the function level attribute will override the default during LLVM IR generation. For example, in the case, where the flag opposes the function attribute, the function attribute will take precendence. The sticky inlining behavior of the speculative_load_hardening attribute may cause a function with the no_speculative_load_hardening attribute to be tagged with the speculative_load_hardening tag in subsequent compiler phases which is desired behavior since the speculative_load_hardening LLVM attribute is designed to be maximally conservative. If both attributes are specified for a function, then an error will be thrown. Reviewers: chandlerc, echristo, kristof.beyls, aaron.ballman Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D54909 llvm-svn: 351565
1 parent 5764982 commit 826ef59

12 files changed

+216
-25
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,12 @@ def SpeculativeLoadHardening : InheritableAttr {
31493149
let Documentation = [SpeculativeLoadHardeningDocs];
31503150
}
31513151

3152+
def NoSpeculativeLoadHardening : InheritableAttr {
3153+
let Spellings = [Clang<"no_speculative_load_hardening">];
3154+
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
3155+
let Documentation = [NoSpeculativeLoadHardeningDocs];
3156+
}
3157+
31523158
def Uninitialized : InheritableAttr {
31533159
let Spellings = [Clang<"uninitialized", 0>];
31543160
let Subjects = SubjectList<[LocalVar]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3822,7 +3822,8 @@ def SpeculativeLoadHardeningDocs : Documentation {
38223822
This attribute can be applied to a function declaration in order to indicate
38233823
that `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
38243824
should be enabled for the function body. This can also be applied to a method
3825-
in Objective C.
3825+
in Objective C. This attribute will take precedence over the command line flag in
3826+
the case where `-mno-speculative-load-hardening <https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mspeculative-load-hardening>`_ is specified.
38263827

38273828
Speculative Load Hardening is a best-effort mitigation against
38283829
information leak attacks that make use of control flow
@@ -3840,6 +3841,42 @@ def SpeculativeLoadHardeningDocs : Documentation {
38403841
}];
38413842
}
38423843

3844+
def NoSpeculativeLoadHardeningDocs : Documentation {
3845+
let Category = DocCatFunction;
3846+
let Content = [{
3847+
This attribute can be applied to a function declaration in order to indicate
3848+
that `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
3849+
is *not* needed for the function body. This can also be applied to a method
3850+
in Objective C. This attribute will take precedence over the command line flag in
3851+
the case where `-mspeculative-load-hardening <https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mspeculative-load-hardening>`_ is specified.
3852+
3853+
Warning: This attribute may not prevent Speculative Load Hardening from being
3854+
enabled for a function which inlines a function that has the
3855+
'speculative_load_hardening' attribute. This is intended to provide a
3856+
maximally conservative model where the code that is marked with the
3857+
'speculative_load_hardening' attribute will always (even when inlined)
3858+
be hardened. A user of this attribute may want to mark functions called by
3859+
a function they do not want to be hardened with the 'noinline' attribute.
3860+
3861+
For example:
3862+
3863+
.. code-block:: c
3864+
3865+
__attribute__((speculative_load_hardening))
3866+
int foo(int i) {
3867+
return i;
3868+
}
3869+
3870+
// Note: bar() may still have speculative load hardening enabled if
3871+
// foo() is inlined into bar(). Mark foo() with __attribute__((noinline))
3872+
// to avoid this situation.
3873+
__attribute__((no_speculative_load_hardening))
3874+
int bar(int i) {
3875+
return foo(i);
3876+
}
3877+
}];
3878+
}
3879+
38433880
def ObjCExternallyRetainedDocs : Documentation {
38443881
let Category = DocCatVariable;
38453882
let Content = [{

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,6 +2496,12 @@ class Sema {
24962496
unsigned AttrSpellingListIndex);
24972497
MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range,
24982498
unsigned AttrSpellingListIndex);
2499+
NoSpeculativeLoadHardeningAttr *
2500+
mergeNoSpeculativeLoadHardeningAttr(Decl *D,
2501+
const NoSpeculativeLoadHardeningAttr &AL);
2502+
SpeculativeLoadHardeningAttr *
2503+
mergeSpeculativeLoadHardeningAttr(Decl *D,
2504+
const SpeculativeLoadHardeningAttr &AL);
24992505
OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
25002506
unsigned AttrSpellingListIndex);
25012507
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);

clang/lib/CodeGen/CGCall.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,8 +1793,6 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
17931793
if (CodeGenOpts.Backchain)
17941794
FuncAttrs.addAttribute("backchain");
17951795

1796-
// FIXME: The interaction of this attribute with the SLH command line flag
1797-
// has not been determined.
17981796
if (CodeGenOpts.SpeculativeLoadHardening)
17991797
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
18001798
}
@@ -1864,8 +1862,6 @@ void CodeGenModule::ConstructAttributeList(
18641862
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
18651863
if (TargetDecl->hasAttr<ConvergentAttr>())
18661864
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
1867-
if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
1868-
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
18691865

18701866
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
18711867
AddAttributesFromFunctionProtoType(
@@ -1910,6 +1906,16 @@ void CodeGenModule::ConstructAttributeList(
19101906

19111907
ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
19121908

1909+
// This must run after constructing the default function attribute list
1910+
// to ensure that the speculative load hardening attribute is removed
1911+
// in the case where the -mspeculative-load-hardening flag was passed.
1912+
if (TargetDecl) {
1913+
if (TargetDecl->hasAttr<NoSpeculativeLoadHardeningAttr>())
1914+
FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening);
1915+
if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
1916+
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
1917+
}
1918+
19131919
if (CodeGenOpts.EnableSegmentedStacks &&
19141920
!(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
19151921
FuncAttrs.addAttribute("split-stack");

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,6 +2489,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
24892489
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
24902490
NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
24912491
UA->getGuid());
2492+
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
2493+
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
2494+
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
2495+
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
24922496
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
24932497
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
24942498

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4157,6 +4157,15 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
41574157
return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
41584158
}
41594159

4160+
NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
4161+
Decl *D, const NoSpeculativeLoadHardeningAttr &AL) {
4162+
if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
4163+
return nullptr;
4164+
4165+
return ::new (Context) NoSpeculativeLoadHardeningAttr(
4166+
AL.getRange(), Context, AL.getSpellingListIndex());
4167+
}
4168+
41604169
OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
41614170
unsigned AttrSpellingListIndex) {
41624171
if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -4177,6 +4186,15 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
41774186
AttrSpellingListIndex);
41784187
}
41794188

4189+
SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
4190+
Decl *D, const SpeculativeLoadHardeningAttr &AL) {
4191+
if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
4192+
return nullptr;
4193+
4194+
return ::new (Context) SpeculativeLoadHardeningAttr(
4195+
AL.getRange(), Context, AL.getSpellingListIndex());
4196+
}
4197+
41804198
static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
41814199
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
41824200
return;
@@ -6618,7 +6636,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
66186636
handleSectionAttr(S, D, AL);
66196637
break;
66206638
case ParsedAttr::AT_SpeculativeLoadHardening:
6621-
handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL);
6639+
handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr,
6640+
NoSpeculativeLoadHardeningAttr>(S, D,
6641+
AL);
6642+
break;
6643+
case ParsedAttr::AT_NoSpeculativeLoadHardening:
6644+
handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr,
6645+
SpeculativeLoadHardeningAttr>(S, D, AL);
66226646
break;
66236647
case ParsedAttr::AT_CodeSeg:
66246648
handleCodeSegAttr(S, D, AL);

clang/test/CodeGen/attr-speculative-load-hardening.cpp

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Check that we correctly set or did not set the attribute for each function.
2+
// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK1
3+
// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK2
4+
5+
// Check that we correctly set or did not set the attribute on each function despite the
6+
// -mspeculative-load-hardening flag.
7+
// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK3
8+
// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK4
9+
10+
11+
// Check that we correctly set or did not set the attribute on each function despite the
12+
// -mno-speculative-load-hardening flag.
13+
// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK5
14+
// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK6
15+
16+
17+
[[clang::speculative_load_hardening]]
18+
int test1() {
19+
return 42;
20+
}
21+
22+
int __attribute__((speculative_load_hardening)) test2() {
23+
return 42;
24+
}
25+
26+
[[clang::no_speculative_load_hardening]]
27+
int test3() {
28+
return 42;
29+
}
30+
31+
int __attribute__((no_speculative_load_hardening)) test4() {
32+
return 42;
33+
}
34+
// CHECK1: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
35+
// CHECK1: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
36+
// CHECK1: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
37+
// CHECK1-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
38+
39+
// CHECK2: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
40+
// CHECK2: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
41+
// CHECK2: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
42+
// CHECK2-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
43+
44+
// CHECK3: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
45+
// CHECK3: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
46+
// CHECK3: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
47+
// CHECK3-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
48+
49+
// CHECK4: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
50+
// CHECK4: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
51+
// CHECK4: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
52+
// CHECK4-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
53+
54+
// CHECK5: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
55+
// CHECK5: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
56+
// CHECK5: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
57+
// CHECK5-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
58+
59+
// CHECK6: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
60+
// CHECK6: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
61+
// CHECK6: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
62+
// CHECK6-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }

clang/test/CodeGen/attr-speculative-load-hardening.m renamed to clang/test/CodeGenObjC/attr-speculative-load-hardening.m

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ int main() __attribute__((speculative_load_hardening)) {
44
return 0;
55
}
66

7-
// SLH: @{{.*}}main{{.*}}[[SLH:#[0-9]+]]
7+
int test() __attribute__((no_speculative_load_hardening)) {
8+
return 0;
9+
}
810

11+
// SLH: @{{.*}}main{{.*}}[[SLH:#[0-9]+]]
12+
// SLH: @{{.*}}test{{.*}}[[NOSLH:#[0-9]+]]
913
// SLH: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
14+
// SLH-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
// CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
8181
// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
8282
// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
83+
// CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
8384
// CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
8485
// CHECK-NEXT: NoStackProtector (SubjectMatchRule_function)
8586
// CHECK-NEXT: NoThreadSafetyAnalysis (SubjectMatchRule_function)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
2+
3+
int i __attribute__((no_speculative_load_hardening)); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
4+
5+
void f1() __attribute__((no_speculative_load_hardening));
6+
void f2() __attribute__((no_speculative_load_hardening(1))); // expected-error {{'no_speculative_load_hardening' attribute takes no arguments}}
7+
8+
template <typename T>
9+
void tf1() __attribute__((no_speculative_load_hardening));
10+
11+
int f3(int __attribute__((no_speculative_load_hardening)), int); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
12+
13+
struct A {
14+
int f __attribute__((no_speculative_load_hardening)); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
15+
void mf1() __attribute__((no_speculative_load_hardening));
16+
static void mf2() __attribute__((no_speculative_load_hardening));
17+
};
18+
19+
int ci [[clang::no_speculative_load_hardening]]; // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
20+
21+
[[clang::no_speculative_load_hardening]] void cf1();
22+
[[clang::no_speculative_load_hardening(1)]] void cf2(); // expected-error {{'no_speculative_load_hardening' attribute takes no arguments}}
23+
24+
template <typename T>
25+
[[clang::no_speculative_load_hardening]]
26+
void ctf1();
27+
28+
int cf3(int c[[clang::no_speculative_load_hardening]], int); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
29+
30+
struct CA {
31+
int f [[clang::no_speculative_load_hardening]]; // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
32+
[[clang::no_speculative_load_hardening]] void mf1();
33+
[[clang::no_speculative_load_hardening]] static void mf2();
34+
};

clang/test/SemaCXX/attr-speculative-load-hardening.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ struct A {
1616
static void mf2() __attribute__((speculative_load_hardening));
1717
};
1818

19+
void f4() __attribute__((no_speculative_load_hardening, speculative_load_hardening)); // expected-error {{attributes are not compatible}}
20+
// expected-note@-1 {{conflicting attribute is here}}
21+
22+
void f5() __attribute__((speculative_load_hardening, no_speculative_load_hardening)); // expected-error {{attributes are not compatible}}
23+
// expected-note@-1 {{conflicting attribute is here}}
24+
25+
void f6() __attribute__((no_speculative_load_hardening));
26+
27+
void f6() __attribute__((speculative_load_hardening)); // expected-error@-2 {{'no_speculative_load_hardening' and 'speculative_load_hardening' attributes are not compatible}}
28+
// expected-note@-1 {{conflicting attribute is here}}
29+
1930
int ci [[clang::speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
2031

2132
[[clang::speculative_load_hardening]] void cf1();
@@ -32,3 +43,16 @@ struct CA {
3243
[[clang::speculative_load_hardening]] void mf1();
3344
[[clang::speculative_load_hardening]] static void mf2();
3445
};
46+
47+
[[clang::speculative_load_hardening, clang::no_speculative_load_hardening]] void cf4(); // expected-error {{attributes are not compatible}}
48+
// expected-note@-1 {{conflicting attribute is here}}
49+
50+
[[clang::no_speculative_load_hardening, clang::speculative_load_hardening]] void cf5(); // expected-error {{attributes are not compatible}}
51+
// expected-note@-1 {{conflicting attribute is here}}
52+
53+
[[clang::speculative_load_hardening]]
54+
void cf6();
55+
56+
[[clang::no_speculative_load_hardening]]
57+
void cf6(); // expected-error@-4 {{'speculative_load_hardening' and 'no_speculative_load_hardening' attributes are not compatible}} \
58+
// expected-note@-1 {{conflicting attribute is here}}

0 commit comments

Comments
 (0)