- Introduce VariadicStringArgument, start using it for no_sanitize; support 
ObjC methods
- Add support for C++11 attribute; fix multiple no_sanitize attribute case


http://reviews.llvm.org/D9631

Files:
  include/clang/AST/Attr.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGen/address-safety-attr.cpp
  test/CodeGen/sanitize-thread-attr.cpp
  test/CodeGenCXX/cfi-vcall.cpp
  test/CodeGenObjC/no-sanitize.m
  test/SemaCXX/attr-no-sanitize.cpp
  utils/TableGen/ClangAttrEmitter.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/AST/Attr.h
===================================================================
--- include/clang/AST/Attr.h
+++ include/clang/AST/Attr.h
@@ -20,6 +20,7 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Sanitizers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/VersionTuple.h"
 #include "llvm/ADT/SmallVector.h"
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -144,6 +144,7 @@
 class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
 class VariadicUnsignedArgument<string name> : Argument<name, 1>;
 class VariadicExprArgument<string name> : Argument<name, 1>;
+class VariadicStringArgument<string name> : Argument<name, 0>;
 
 // A version of the form major.minor[.subminor].
 class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
@@ -1386,6 +1387,24 @@
   let Documentation = [Undocumented];
 }
 
+def NoSanitize : InheritableAttr {
+  let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">];
+  let Args = [VariadicStringArgument<"Sanitizers">];
+  let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
+  let Documentation = [NoSanitizeDocs];
+  let AdditionalMembers = [{
+    SanitizerMask getMask() const {
+      SanitizerMask Mask = 0;
+      for (auto SanitizerName : sanitizers()) {
+        SanitizerMask ParsedMask =
+            parseSanitizerValue(SanitizerName, /*AllowGroups=*/true);
+        Mask |= expandSanitizerGroups(ParsedMask);
+      }
+      return Mask;
+    }
+  }];
+}
+
 // Attribute to disable AddressSanitizer (or equivalent) checks.
 def NoSanitizeAddress : InheritableAttr {
   let Spellings = [GCC<"no_address_safety_analysis">,
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -920,6 +920,19 @@
   }];
 }
 
+def NoSanitizeDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Use the ``no_sanitize`` attribute on a function declaration to specify
+that a particular instrumentation or set of instrumentations should not be
+applied to that function. The attribute takes a list of string literals,
+which have the same meaning as values accepted by the ``-fno-sanitize=``
+flag. For example, ``__attribute__((no_sanitize("address", "thread")))``
+specifies that AddressSanitizer and ThreadSanitizer should not be applied
+to the function.
+  }];
+}
+
 def NoSanitizeAddressDocs : Documentation {
   let Category = DocCatFunction;
   // This function has multiple distinct spellings, and so it requires a custom
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -608,6 +608,28 @@
   if (CGM.isInSanitizerBlacklist(Fn, Loc))
     SanOpts.clear();
 
+  if (D) {
+    // Apply the no_sanitize* attributes to SanOpts.
+    for (auto I = D->specific_attr_begin<NoSanitizeAttr>(),
+              E = D->specific_attr_end<NoSanitizeAttr>();
+         I != E; ++I)
+      SanOpts.Mask &= ~I->getMask();
+    if (D->hasAttr<NoSanitizeAddressAttr>())
+      SanOpts.set(SanitizerKind::Address, false);
+    if (D->hasAttr<NoSanitizeThreadAttr>())
+      SanOpts.set(SanitizerKind::Thread, false);
+    if (D->hasAttr<NoSanitizeMemoryAttr>())
+      SanOpts.set(SanitizerKind::Memory, false);
+  }
+
+  // Apply sanitizer attributes to the function.
+  if (SanOpts.has(SanitizerKind::Address))
+    Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+  if (SanOpts.has(SanitizerKind::Thread))
+    Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+  if (SanOpts.has(SanitizerKind::Memory))
+    Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+
   // Pass inline keyword to optimizer if it appears explicitly on any
   // declaration. Also, in the case of -fno-inline attach NoInline
   // attribute to all function that are not marked AlwaysInline.
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -752,23 +752,6 @@
   else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
     B.addAttribute(llvm::Attribute::StackProtectReq);
 
-  // Add sanitizer attributes if function is not blacklisted.
-  if (!isInSanitizerBlacklist(F, D->getLocation())) {
-    // When AddressSanitizer is enabled, set SanitizeAddress attribute
-    // unless __attribute__((no_sanitize_address)) is used.
-    if (LangOpts.Sanitize.has(SanitizerKind::Address) &&
-        !D->hasAttr<NoSanitizeAddressAttr>())
-      B.addAttribute(llvm::Attribute::SanitizeAddress);
-    // Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
-    if (LangOpts.Sanitize.has(SanitizerKind::Thread) &&
-        !D->hasAttr<NoSanitizeThreadAttr>())
-      B.addAttribute(llvm::Attribute::SanitizeThread);
-    // Same for MemorySanitizer and __attribute__((no_sanitize_memory))
-    if (LangOpts.Sanitize.has(SanitizerKind::Memory) &&
-        !D->hasAttr<NoSanitizeMemoryAttr>())
-      B.addAttribute(llvm::Attribute::SanitizeMemory);
-  }
-
   F->addAttributes(llvm::AttributeSet::FunctionIndex,
                    llvm::AttributeSet::get(
                        F->getContext(), llvm::AttributeSet::FunctionIndex, B));
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4354,6 +4354,24 @@
   handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
 }
 
+static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  std::vector<std::string> Sanitizers;
+
+  for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
+    StringRef SanitizerName;
+    SourceLocation LiteralLoc;
+
+    if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc))
+      return;
+
+    Sanitizers.push_back(SanitizerName);
+  }
+
+  D->addAttr(::new (S.Context) NoSanitizeAttr(
+      Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(),
+      Attr.getAttributeSpellingListIndex()));
+}
+
 /// Handles semantic checking for features that are common to all attributes,
 /// such as checking whether a parameter was properly specified, or the correct
 /// number of arguments were passed, etc.
@@ -4822,6 +4840,9 @@
   case AttributeList::AT_ScopedLockable:
     handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr);
     break;
+  case AttributeList::AT_NoSanitize:
+    handleNoSanitizeAttr(S, D, Attr);
+    break;
   case AttributeList::AT_NoSanitizeAddress:
     handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr);
     break;
Index: test/CodeGen/address-safety-attr.cpp
===================================================================
--- test/CodeGen/address-safety-attr.cpp
+++ test/CodeGen/address-safety-attr.cpp
@@ -52,6 +52,21 @@
 int NoAddressSafety2(int *a);
 int NoAddressSafety2(int *a) { return *a; }
 
+// WITHOUT:  NoAddressSafety3{{.*}}) [[NOATTR]]
+// BLFILE:  NoAddressSafety3{{.*}}) [[NOATTR]]
+// BLFUNC:  NoAddressSafety3{{.*}}) [[NOATTR]]
+// ASAN:  NoAddressSafety3{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize("address")))
+int NoAddressSafety3(int *a) { return *a; }
+
+// WITHOUT:  NoAddressSafety4{{.*}}) [[NOATTR]]
+// BLFILE:  NoAddressSafety4{{.*}}) [[NOATTR]]
+// BLFUNC:  NoAddressSafety4{{.*}}) [[NOATTR]]
+// ASAN:  NoAddressSafety4{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize("address")))
+int NoAddressSafety4(int *a);
+int NoAddressSafety4(int *a) { return *a; }
+
 // WITHOUT:  AddressSafetyOk{{.*}}) [[NOATTR]]
 // BLFILE:  AddressSafetyOk{{.*}}) [[NOATTR]]
 // BLFUNC: AddressSafetyOk{{.*}}) [[WITH]]
@@ -86,16 +101,25 @@
 template<int i>
 int TemplateAddressSafetyOk() { return i; }
 
-// WITHOUT:  TemplateNoAddressSafety{{.*}}) [[NOATTR]]
-// BLFILE:  TemplateNoAddressSafety{{.*}}) [[NOATTR]]
-// BLFUNC:  TemplateNoAddressSafety{{.*}}) [[NOATTR]]
-// ASAN: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// WITHOUT:  TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
+// BLFILE:  TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
+// BLFUNC:  TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
+// ASAN: TemplateNoAddressSafety1{{.*}}) [[NOATTR]]
 template<int i>
 __attribute__((no_sanitize_address))
-int TemplateNoAddressSafety() { return i; }
+int TemplateNoAddressSafety1() { return i; }
+
+// WITHOUT:  TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFILE:  TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFUNC:  TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
+// ASAN: TemplateNoAddressSafety2{{.*}}) [[NOATTR]]
+template<int i>
+__attribute__((no_sanitize("address")))
+int TemplateNoAddressSafety2() { return i; }
 
 int force_instance = TemplateAddressSafetyOk<42>()
-                   + TemplateNoAddressSafety<42>();
+                   + TemplateNoAddressSafety1<42>()
+                   + TemplateNoAddressSafety2<42>();
 
 // Check that __cxx_global_var_init* get the sanitize_address attribute.
 int global1 = 0;
Index: test/CodeGen/sanitize-thread-attr.cpp
===================================================================
--- test/CodeGen/sanitize-thread-attr.cpp
+++ test/CodeGen/sanitize-thread-attr.cpp
@@ -22,6 +22,12 @@
 int NoTSAN2(int *a);
 int NoTSAN2(int *a) { return *a; }
 
+// WITHOUT:  NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// BL:  NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// TSAN:  NoTSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize("thread")))
+int NoTSAN3(int *a) { return *a; }
+
 // WITHOUT:  TSANOk{{.*}}) [[NOATTR]]
 // BL:  TSANOk{{.*}}) [[NOATTR]]
 // TSAN: TSANOk{{.*}}) [[WITH:#[0-9]+]]
Index: test/CodeGenCXX/cfi-vcall.cpp
===================================================================
--- test/CodeGenCXX/cfi-vcall.cpp
+++ test/CodeGenCXX/cfi-vcall.cpp
@@ -47,16 +47,32 @@
   a->f();
 }
 
-// CHECK: define internal void @_Z2dfPN12_GLOBAL__N_11DE
-void df(D *d) {
+// CHECK: define internal void @_Z3df1PN12_GLOBAL__N_11DE
+void df1(D *d) {
   // CHECK: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE")
   d->f();
 }
 
+// CHECK: define internal void @_Z3df2PN12_GLOBAL__N_11DE
+__attribute__((no_sanitize("cfi")))
+void df2(D *d) {
+  // CHECK-NOT: call i1 @llvm.bitset.test
+  d->f();
+}
+
+// CHECK: define internal void @_Z3df3PN12_GLOBAL__N_11DE
+__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
+void df3(D *d) {
+  // CHECK-NOT: call i1 @llvm.bitset.test
+  d->f();
+}
+
 D d;
 
 void foo() {
-  df(&d);
+  df1(&d);
+  df2(&d);
+  df3(&d);
 }
 
 // CHECK-DAG: !{!"1A", [3 x i8*]* @_ZTV1A, i64 16}
Index: test/CodeGenObjC/no-sanitize.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/no-sanitize.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -fsanitize=address -o - | FileCheck %s
+
+@interface I0 @end
+@implementation I0
+// CHECK-NOT: sanitize_address
+- (void) im0: (int) a0 __attribute__((no_sanitize("address"))) {
+}
+@end
Index: test/SemaCXX/attr-no-sanitize.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-no-sanitize.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -std=c++11 -ast-dump %s 2>&1 | FileCheck --check-prefix=DUMP %s
+// RUN: not %clang_cc1 -std=c++11 -ast-print %s 2>&1 | FileCheck --check-prefix=PRINT %s
+
+int v1 __attribute__((no_sanitize("address"))); // expected-error{{'no_sanitize' attribute only applies to functions and methods}}
+
+int f1() __attribute__((no_sanitize)); // expected-error{{'no_sanitize' attribute takes at least 1 argument}}
+
+int f2() __attribute__((no_sanitize(1))); // expected-error{{'no_sanitize' attribute requires a string}}
+
+// DUMP-LABEL: FunctionDecl {{.*}} f3
+// DUMP: NoSanitizeAttr {{.*}} address
+// PRINT: int f3() __attribute__((no_sanitize("address")))
+int f3() __attribute__((no_sanitize("address")));
+
+// DUMP-LABEL: FunctionDecl {{.*}} f4
+// DUMP: NoSanitizeAttr {{.*}} thread
+// PRINT: int f4() {{\[\[}}clang::no_sanitize("thread")]]
+[[clang::no_sanitize("thread")]] int f4();
+
+// DUMP-LABEL: FunctionDecl {{.*}} f5
+// DUMP: NoSanitizeAttr {{.*}} address thread
+// PRINT: int f5() __attribute__((no_sanitize("address", "thread")))
+int f5() __attribute__((no_sanitize("address", "thread")));
+
+// DUMP-LABEL: FunctionDecl {{.*}} f6
+// DUMP: NoSanitizeAttr {{.*}} unknown
+// PRINT: int f6() __attribute__((no_sanitize("unknown")))
+int f6() __attribute__((no_sanitize("unknown")));
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -82,6 +82,7 @@
     .Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
     .Case("Expr *", "ReadExpr(F)")
     .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
+    .Case("std::string", "ReadString(Record, Idx)")
     .Default("Record[Idx++]");
 }
 
@@ -95,6 +96,7 @@
     .Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
     .Case("IdentifierInfo *", 
           "AddIdentifierRef(" + std::string(name) + ", Record);\n")
+    .Case("std::string", "AddString(" + std::string(name) + ", Record);\n")
     .Default("Record.push_back(" + std::string(name) + ");\n");
 }
 
@@ -983,6 +985,16 @@
     }
   };
 
+  class VariadicStringArgument : public VariadicArgument {
+  public:
+    VariadicStringArgument(const Record &Arg, StringRef Attr)
+      : VariadicArgument(Arg, Attr, "std::string")
+    {}
+    void writeValueImpl(raw_ostream &OS) const override {
+      OS << "    OS << \"\\\"\" << Val << \"\\\"\";\n";
+    }
+  };
+
   class TypeArgument : public SimpleArgument {
   public:
     TypeArgument(const Record &Arg, StringRef Attr)
@@ -1044,6 +1056,8 @@
     Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
   else if (ArgName == "VariadicUnsignedArgument")
     Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
+  else if (ArgName == "VariadicStringArgument")
+    Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr);
   else if (ArgName == "VariadicEnumArgument")
     Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
   else if (ArgName == "VariadicExprArgument")
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to