This revision was automatically updated to reflect the committed changes.
Closed by commit rC351565: [clang][slh] add Clang attr 
no_speculative_load_hardening (authored by zbrid, committed by ).
Herald added a subscriber: cfe-commits.

Changed prior to commit:
  https://reviews.llvm.org/D54909?vs=182060&id=182539#toc

Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D54909/new/

https://reviews.llvm.org/D54909

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Sema/Sema.h
  lib/CodeGen/CGCall.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGen/attr-speculative-load-hardening.cpp
  test/CodeGen/attr-speculative-load-hardening.m
  test/CodeGenCXX/attr-speculative-load-hardening.cpp
  test/CodeGenObjC/attr-speculative-load-hardening.m
  test/Misc/pragma-attribute-supported-attributes-list.test
  test/SemaCXX/attr-no-speculative-load-hardening.cpp
  test/SemaCXX/attr-speculative-load-hardening.cpp

Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -1793,8 +1793,6 @@
     if (CodeGenOpts.Backchain)
       FuncAttrs.addAttribute("backchain");
 
-    // FIXME: The interaction of this attribute with the SLH command line flag
-    // has not been determined.
     if (CodeGenOpts.SpeculativeLoadHardening)
       FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
   }
@@ -1864,8 +1862,6 @@
       FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
     if (TargetDecl->hasAttr<ConvergentAttr>())
       FuncAttrs.addAttribute(llvm::Attribute::Convergent);
-    if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
-      FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
 
     if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
       AddAttributesFromFunctionProtoType(
@@ -1910,6 +1906,16 @@
 
   ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
 
+  // This must run after constructing the default function attribute list
+  // to ensure that the speculative load hardening attribute is removed
+  // in the case where the -mspeculative-load-hardening flag was passed.
+  if (TargetDecl) {
+    if (TargetDecl->hasAttr<NoSpeculativeLoadHardeningAttr>())
+      FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening);
+    if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
+      FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
+  }
+
   if (CodeGenOpts.EnableSegmentedStacks &&
       !(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
     FuncAttrs.addAttribute("split-stack");
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2489,6 +2489,10 @@
   else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
     NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
                               UA->getGuid());
+  else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
+    NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
+  else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
+    NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
   else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
     NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
 
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4157,6 +4157,15 @@
   return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
 }
 
+NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
+    Decl *D, const NoSpeculativeLoadHardeningAttr &AL) {
+  if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
+    return nullptr;
+
+  return ::new (Context) NoSpeculativeLoadHardeningAttr(
+      AL.getRange(), Context, AL.getSpellingListIndex());
+}
+
 OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
                                               unsigned AttrSpellingListIndex) {
   if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -4177,6 +4186,15 @@
                                           AttrSpellingListIndex);
 }
 
+SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
+    Decl *D, const SpeculativeLoadHardeningAttr &AL) {
+  if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
+    return nullptr;
+
+  return ::new (Context) SpeculativeLoadHardeningAttr(
+      AL.getRange(), Context, AL.getSpellingListIndex());
+}
+
 static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
     return;
@@ -6618,7 +6636,13 @@
     handleSectionAttr(S, D, AL);
     break;
   case ParsedAttr::AT_SpeculativeLoadHardening:
-    handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL);
+    handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr,
+                                        NoSpeculativeLoadHardeningAttr>(S, D,
+                                                                        AL);
+    break;
+  case ParsedAttr::AT_NoSpeculativeLoadHardening:
+    handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr,
+                                        SpeculativeLoadHardeningAttr>(S, D, AL);
     break;
   case ParsedAttr::AT_CodeSeg:
     handleCodeSegAttr(S, D, AL);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2496,6 +2496,12 @@
                                           unsigned AttrSpellingListIndex);
   MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range,
                                 unsigned AttrSpellingListIndex);
+  NoSpeculativeLoadHardeningAttr *
+  mergeNoSpeculativeLoadHardeningAttr(Decl *D,
+                                      const NoSpeculativeLoadHardeningAttr &AL);
+  SpeculativeLoadHardeningAttr *
+  mergeSpeculativeLoadHardeningAttr(Decl *D,
+                                    const SpeculativeLoadHardeningAttr &AL);
   OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
                                           unsigned AttrSpellingListIndex);
   InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3822,7 +3822,8 @@
   This attribute can be applied to a function declaration in order to indicate
   that `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
   should be enabled for the function body. This can also be applied to a method
-  in Objective C.
+  in Objective C. This attribute will take precedence over the command line flag in
+  the case where `-mno-speculative-load-hardening <https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mspeculative-load-hardening>`_ is specified.
 
   Speculative Load Hardening is a best-effort mitigation against
   information leak attacks that make use of control flow
@@ -3840,6 +3841,42 @@
   }];
 }
 
+def NoSpeculativeLoadHardeningDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+  This attribute can be applied to a function declaration in order to indicate
+  that `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
+  is *not* needed for the function body. This can also be applied to a method
+  in Objective C. This attribute will take precedence over the command line flag in
+  the case where `-mspeculative-load-hardening <https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mspeculative-load-hardening>`_ is specified.
+
+  Warning: This attribute may not prevent Speculative Load Hardening from being
+  enabled for a function which inlines a function that has the
+  'speculative_load_hardening' attribute. This is intended to provide a
+  maximally conservative model where the code that is marked with the
+  'speculative_load_hardening' attribute will always (even when inlined)
+  be hardened. A user of this attribute may want to mark functions called by
+  a function they do not want to be hardened with the 'noinline' attribute.
+
+  For example:
+
+  .. code-block:: c
+
+    __attribute__((speculative_load_hardening))
+    int foo(int i) {
+      return i;
+    }
+
+    // Note: bar() may still have speculative load hardening enabled if
+    // foo() is inlined into bar(). Mark foo() with __attribute__((noinline))
+    // to avoid this situation.
+    __attribute__((no_speculative_load_hardening))
+    int bar(int i) {
+      return foo(i);
+    }
+  }];
+}
+
 def ObjCExternallyRetainedDocs : Documentation {
   let Category = DocCatVariable;
   let Content = [{
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -3149,6 +3149,12 @@
   let Documentation = [SpeculativeLoadHardeningDocs];
 }
 
+def NoSpeculativeLoadHardening : InheritableAttr {
+  let Spellings = [Clang<"no_speculative_load_hardening">];
+  let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
+  let Documentation = [NoSpeculativeLoadHardeningDocs];
+}
+
 def Uninitialized : InheritableAttr {
   let Spellings = [Clang<"uninitialized", 0>];
   let Subjects = SubjectList<[LocalVar]>;
Index: test/SemaCXX/attr-no-speculative-load-hardening.cpp
===================================================================
--- test/SemaCXX/attr-no-speculative-load-hardening.cpp
+++ test/SemaCXX/attr-no-speculative-load-hardening.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+int i __attribute__((no_speculative_load_hardening)); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+
+void f1() __attribute__((no_speculative_load_hardening));
+void f2() __attribute__((no_speculative_load_hardening(1))); // expected-error {{'no_speculative_load_hardening' attribute takes no arguments}}
+
+template <typename T>
+void tf1() __attribute__((no_speculative_load_hardening));
+
+int f3(int __attribute__((no_speculative_load_hardening)), int); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+
+struct A {
+  int f __attribute__((no_speculative_load_hardening));  // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+  void mf1() __attribute__((no_speculative_load_hardening));
+  static void mf2() __attribute__((no_speculative_load_hardening));
+};
+
+int ci [[clang::no_speculative_load_hardening]]; // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+
+[[clang::no_speculative_load_hardening]] void cf1();
+[[clang::no_speculative_load_hardening(1)]] void cf2(); // expected-error {{'no_speculative_load_hardening' attribute takes no arguments}}
+
+template <typename T>
+[[clang::no_speculative_load_hardening]]
+void ctf1();
+
+int cf3(int c[[clang::no_speculative_load_hardening]], int); // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+
+struct CA {
+  int f [[clang::no_speculative_load_hardening]];  // expected-error {{'no_speculative_load_hardening' attribute only applies to functions}}
+  [[clang::no_speculative_load_hardening]] void mf1();
+  [[clang::no_speculative_load_hardening]] static void mf2();
+};
Index: test/SemaCXX/attr-speculative-load-hardening.cpp
===================================================================
--- test/SemaCXX/attr-speculative-load-hardening.cpp
+++ test/SemaCXX/attr-speculative-load-hardening.cpp
@@ -16,6 +16,17 @@
   static void mf2() __attribute__((speculative_load_hardening));
 };
 
+void f4() __attribute__((no_speculative_load_hardening, speculative_load_hardening)); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+void f5() __attribute__((speculative_load_hardening, no_speculative_load_hardening)); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+void f6() __attribute__((no_speculative_load_hardening));
+
+void f6() __attribute__((speculative_load_hardening)); // expected-error@-2 {{'no_speculative_load_hardening' and 'speculative_load_hardening' attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
 int ci [[clang::speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
 
 [[clang::speculative_load_hardening]] void cf1();
@@ -32,3 +43,16 @@
   [[clang::speculative_load_hardening]] void mf1();
   [[clang::speculative_load_hardening]] static void mf2();
 };
+
+[[clang::speculative_load_hardening, clang::no_speculative_load_hardening]] void cf4();  // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+[[clang::no_speculative_load_hardening, clang::speculative_load_hardening]] void cf5();  // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+[[clang::speculative_load_hardening]]
+void cf6();
+
+[[clang::no_speculative_load_hardening]]
+void cf6(); // expected-error@-4 {{'speculative_load_hardening' and 'no_speculative_load_hardening' attributes are not compatible}} \
+// expected-note@-1 {{conflicting attribute is here}}
Index: test/CodeGenObjC/attr-speculative-load-hardening.m
===================================================================
--- test/CodeGenObjC/attr-speculative-load-hardening.m
+++ test/CodeGenObjC/attr-speculative-load-hardening.m
@@ -0,0 +1,14 @@
+// RUN: %clang -emit-llvm %s -o - -S | FileCheck %s -check-prefix=SLH
+
+int main() __attribute__((speculative_load_hardening)) {
+  return 0;
+}
+
+int test() __attribute__((no_speculative_load_hardening)) {
+  return 0;
+}
+
+// SLH: @{{.*}}main{{.*}}[[SLH:#[0-9]+]]
+// SLH: @{{.*}}test{{.*}}[[NOSLH:#[0-9]+]]
+// SLH: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// SLH-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
Index: test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- test/Misc/pragma-attribute-supported-attributes-list.test
+++ test/Misc/pragma-attribute-supported-attributes-list.test
@@ -80,6 +80,7 @@
 // CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
 // CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
 // CHECK-NEXT: NoStackProtector (SubjectMatchRule_function)
 // CHECK-NEXT: NoThreadSafetyAnalysis (SubjectMatchRule_function)
Index: test/CodeGenCXX/attr-speculative-load-hardening.cpp
===================================================================
--- test/CodeGenCXX/attr-speculative-load-hardening.cpp
+++ test/CodeGenCXX/attr-speculative-load-hardening.cpp
@@ -0,0 +1,62 @@
+// Check that we correctly set or did not set the attribute for each function.
+// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK1
+// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK2
+
+// Check that we correctly set or did not set the attribute on each function despite the
+// -mspeculative-load-hardening flag.
+// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK3
+// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK4
+
+
+// Check that we correctly set or did not set the attribute on each function despite the
+// -mno-speculative-load-hardening flag.
+// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK5
+// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK6
+
+
+[[clang::speculative_load_hardening]]
+int test1() {
+  return 42;
+}
+
+int __attribute__((speculative_load_hardening)) test2() {
+  return 42;
+}
+
+[[clang::no_speculative_load_hardening]]
+int test3() {
+  return 42;
+}
+
+int __attribute__((no_speculative_load_hardening)) test4() {
+  return 42;
+}
+// CHECK1: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
+// CHECK1: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK1: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK1-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+
+// CHECK2: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
+// CHECK2: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK2: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK2-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+
+// CHECK3: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
+// CHECK3: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK3: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK3-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+
+// CHECK4: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
+// CHECK4: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK4: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK4-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+
+// CHECK5: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]]
+// CHECK5: @{{.*}}test3{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK5: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK5-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+
+// CHECK6: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]]
+// CHECK6: @{{.*}}test4{{.*}}[[NOSLH:#[0-9]+]]
+// CHECK6: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
+// CHECK6-NOT: attributes [[NOSLH]] = { {{.*}}speculative_load_hardening{{.*}} }
Index: test/CodeGen/attr-speculative-load-hardening.cpp
===================================================================
--- test/CodeGen/attr-speculative-load-hardening.cpp
+++ test/CodeGen/attr-speculative-load-hardening.cpp
@@ -1,18 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK1
-// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK2
-//
-// Check that we set the attribute on each function.
-
-[[clang::speculative_load_hardening]]
-int test1() {
-  return 42;
-}
-
-int __attribute__((speculative_load_hardening)) test2() {
-  return 42;
-}
-// CHECK1: @{{.*}}test1{{.*}}[[SLH1:#[0-9]+]]
-// CHECK1: attributes [[SLH1]] = { {{.*}}speculative_load_hardening{{.*}} }
-
-// CHECK2: @{{.*}}test2{{.*}}[[SLH2:#[0-9]+]]
-// CHECK2: attributes [[SLH2]] = { {{.*}}speculative_load_hardening{{.*}} }
Index: test/CodeGen/attr-speculative-load-hardening.m
===================================================================
--- test/CodeGen/attr-speculative-load-hardening.m
+++ test/CodeGen/attr-speculative-load-hardening.m
@@ -1,9 +0,0 @@
-// RUN: %clang -emit-llvm %s -o - -S | FileCheck %s -check-prefix=SLH
-
-int main() __attribute__((speculative_load_hardening)) {
-  return 0;
-}
-
-// SLH: @{{.*}}main{{.*}}[[SLH:#[0-9]+]]
-
-// SLH: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to