[Sanitizer] Refactor SuppressionContext class.
authorAlexey Samsonov <vonosmas@gmail.com>
Fri, 20 Feb 2015 17:41:59 +0000 (17:41 +0000)
committerAlexey Samsonov <vonosmas@gmail.com>
Fri, 20 Feb 2015 17:41:59 +0000 (17:41 +0000)
SuppressionContext is no longer a singleton, shared by all sanitizers,
but a regular class. Each of ASan, LSan, UBSan and TSan now have their
own SuppressionContext, which only parses suppressions specific to
that sanitizer.

"suppressions" flag is moved away from common flags into tool-specific
flags, so the user now may pass
  ASAN_OPTIONS=suppressions=asan_supp.txt LSAN_OPIONS=suppressions=lsan_supp.txt
in a single invocation.

llvm-svn: 230026

18 files changed:
compiler-rt/lib/asan/asan_flags.inc
compiler-rt/lib/asan/asan_suppressions.cc
compiler-rt/lib/lsan/lsan_common.cc
compiler-rt/lib/lsan/lsan_flags.inc
compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
compiler-rt/lib/tsan/rtl/tsan_flags.inc
compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
compiler-rt/lib/tsan/rtl/tsan_suppressions.h
compiler-rt/lib/ubsan/ubsan_diag.cc
compiler-rt/lib/ubsan/ubsan_diag.h
compiler-rt/lib/ubsan/ubsan_flags.inc
compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
compiler-rt/lib/ubsan/ubsan_init.cc
compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp

index ec9d419..53a8a40 100644 (file)
@@ -142,3 +142,4 @@ ASAN_FLAG(int, detect_odr_violation, 2,
           "have different sizes")
 ASAN_FLAG(bool, dump_instruction_bytes, false,
           "If true, dump 16 bytes starting at the instruction that caused SEGV")
+ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
index ef55471..62198ae 100644 (file)
 #include "asan_suppressions.h"
 
 #include "asan_stack.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
 namespace __asan {
 
-static bool suppressions_inited = false;
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kInterceptorName[] = "interceptor_name";
+static const char kInterceptorViaFunction[] = "interceptor_via_fun";
+static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
+static const char *kSuppressionTypes[] = {
+    kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary};
 
 void InitializeSuppressions() {
-  CHECK(!suppressions_inited);
-  SuppressionContext::InitIfNecessary();
-  suppressions_inited = true;
+  CHECK_EQ(nullptr, suppression_ctx);
+  suppression_ctx = new (suppression_placeholder)  // NOLINT
+      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+  suppression_ctx->ParseFromFile(flags()->suppressions);
 }
 
 bool IsInterceptorSuppressed(const char *interceptor_name) {
-  CHECK(suppressions_inited);
-  SuppressionContext *ctx = SuppressionContext::Get();
+  CHECK(suppression_ctx);
   Suppression *s;
   // Match "interceptor_name" suppressions.
-  return ctx->Match(interceptor_name, SuppressionInterceptorName, &s);
+  return suppression_ctx->Match(interceptor_name, kInterceptorName, &s);
 }
 
 bool HaveStackTraceBasedSuppressions() {
-  CHECK(suppressions_inited);
-  SuppressionContext *ctx = SuppressionContext::Get();
-  return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) ||
-         ctx->HasSuppressionType(SuppressionInterceptorViaLibrary);
+  CHECK(suppression_ctx);
+  return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) ||
+         suppression_ctx->HasSuppressionType(kInterceptorViaLibrary);
 }
 
 bool IsStackTraceSuppressed(const StackTrace *stack) {
-  CHECK(suppressions_inited);
   if (!HaveStackTraceBasedSuppressions())
     return false;
 
-  SuppressionContext *ctx = SuppressionContext::Get();
+  CHECK(suppression_ctx);
   Symbolizer *symbolizer = Symbolizer::GetOrInit();
   Suppression *s;
   for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
     uptr addr = stack->trace[i];
 
-    if (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) {
+    if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
       const char *module_name;
       uptr module_offset;
       // Match "interceptor_via_lib" suppressions.
       if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
                                                   &module_offset) &&
-          ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) {
+          suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) {
         return true;
       }
     }
 
-    if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) {
+    if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
       SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
       for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
         const char *function_name = cur->info.function;
@@ -73,7 +78,8 @@ bool IsStackTraceSuppressed(const StackTrace *stack) {
           continue;
         }
         // Match "interceptor_via_fun" suppressions.
-        if (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) {
+        if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
+                                   &s)) {
           frames->ClearAll();
           return true;
         }
index 6dafb84..b9e2a11 100644 (file)
@@ -60,14 +60,23 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
     if (flags()->log_threads) Report(__VA_ARGS__); \
   } while (0);
 
-static bool suppressions_inited = false;
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kSuppressionLeak[] = "leak";
+static const char *kSuppressionTypes[] = { kSuppressionLeak };
 
 void InitializeSuppressions() {
-  CHECK(!suppressions_inited);
-  SuppressionContext::InitIfNecessary();
+  CHECK_EQ(nullptr, suppression_ctx);
+  suppression_ctx = new (suppression_placeholder) // NOLINT
+      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+  suppression_ctx->ParseFromFile(flags()->suppressions);
   if (&__lsan_default_suppressions)
-    SuppressionContext::Get()->Parse(__lsan_default_suppressions());
-  suppressions_inited = true;
+    suppression_ctx->Parse(__lsan_default_suppressions());
+}
+
+static SuppressionContext *GetSuppressionContext() {
+  CHECK(suppression_ctx);
+  return suppression_ctx;
 }
 
 struct RootRegion {
@@ -350,7 +359,7 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
 
 static void PrintMatchedSuppressions() {
   InternalMmapVector<Suppression *> matched(1);
-  SuppressionContext::Get()->GetMatched(&matched);
+  GetSuppressionContext()->GetMatched(&matched);
   if (!matched.size())
     return;
   const char *line = "-----------------------------------------------------";
@@ -429,17 +438,17 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
   // Suppress by module name.
   const char *module_name;
   uptr module_offset;
+  SuppressionContext *suppressions = GetSuppressionContext();
   if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name,
                                                            &module_offset) &&
-      SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s))
+      suppressions->Match(module_name, kSuppressionLeak, &s))
     return s;
 
   // Suppress by file or function name.
   SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
   for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
-    if (SuppressionContext::Get()->Match(cur->info.function, SuppressionLeak,
-                                         &s) ||
-        SuppressionContext::Get()->Match(cur->info.file, SuppressionLeak, &s)) {
+    if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
+        suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
       break;
     }
   }
index 7f00acb..b19b345 100644 (file)
@@ -42,3 +42,4 @@ LSAN_FLAG(bool, use_poisoned, false,
           "Consider pointers found in poisoned memory to be valid.")
 LSAN_FLAG(bool, log_pointers, false, "Debug logging")
 LSAN_FLAG(bool, log_threads, false, "Debug logging")
+LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
index e8c8a87..58f7f37 100644 (file)
@@ -128,7 +128,6 @@ COMMON_FLAG(const char *, coverage_dir, ".",
 COMMON_FLAG(bool, full_address_space, false,
             "Sanitize complete address space; "
             "by default kernel area on 32-bit platforms will not be sanitized")
-COMMON_FLAG(const char *, suppressions, "", "Suppressions file name.")
 COMMON_FLAG(bool, print_suppressions, true,
             "Print matched suppressions at exit.")
 COMMON_FLAG(
index ec4789c..2b697e9 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Suppression parsing/matching code shared between TSan and LSan.
+// Suppression parsing/matching code.
 //
 //===----------------------------------------------------------------------===//
 
 
 namespace __sanitizer {
 
-static const char *const kTypeStrings[SuppressionTypeCount] = {
-    "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib",
-    "deadlock", "vptr_check", "interceptor_name", "interceptor_via_fun",
-    "interceptor_via_lib"};
-
-ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
-static SuppressionContext *suppression_ctx = 0;
-
-SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) {
-  internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_));
-}
-
-SuppressionContext *SuppressionContext::Get() {
-  CHECK(suppression_ctx);
-  return suppression_ctx;
+SuppressionContext::SuppressionContext(const char *suppression_types[],
+                                       int suppression_types_num)
+    : suppression_types_(suppression_types),
+      suppression_types_num_(suppression_types_num), suppressions_(1),
+      can_parse_(true) {
+  CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
+  internal_memset(has_suppression_type_, 0, suppression_types_num_);
 }
 
-void SuppressionContext::InitIfNecessary() {
-  if (suppression_ctx)
+void SuppressionContext::ParseFromFile(const char *filename) {
+  if (filename[0] == '\0')
     return;
-  suppression_ctx = new(placeholder) SuppressionContext;
-  if (common_flags()->suppressions[0] == '\0')
-    return;
-  char *suppressions_from_file;
+  char *file_contents;
   uptr buffer_size;
-  uptr contents_size =
-      ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
-                       &buffer_size, 1 << 26 /* max_len */);
+  uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
+                                        1 << 26 /* max_len */);
   if (contents_size == 0) {
     Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
-           common_flags()->suppressions);
+           filename);
     Die();
   }
-  suppression_ctx->Parse(suppressions_from_file);
+  Parse(file_contents);
 }
 
-bool SuppressionContext::Match(const char *str, SuppressionType type,
+bool SuppressionContext::Match(const char *str, const char *type,
                                Suppression **s) {
-  if (!has_suppresson_type_[type])
-    return false;
   can_parse_ = false;
-  uptr i;
-  for (i = 0; i < suppressions_.size(); i++)
-    if (type == suppressions_[i].type &&
-        TemplateMatch(suppressions_[i].templ, str))
-      break;
-  if (i == suppressions_.size()) return false;
-  *s = &suppressions_[i];
-  return true;
+  if (!HasSuppressionType(type))
+    return false;
+  for (uptr i = 0; i < suppressions_.size(); i++) {
+    Suppression &cur = suppressions_[i];
+    if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
+      *s = &cur;
+      return true;
+    }
+  }
+  return false;
 }
 
 static const char *StripPrefix(const char *str, const char *prefix) {
@@ -97,26 +85,26 @@ void SuppressionContext::Parse(const char *str) {
       while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
         end2--;
       int type;
-      for (type = 0; type < SuppressionTypeCount; type++) {
-        const char *next_char = StripPrefix(line, kTypeStrings[type]);
+      for (type = 0; type < suppression_types_num_; type++) {
+        const char *next_char = StripPrefix(line, suppression_types_[type]);
         if (next_char && *next_char == ':') {
           line = ++next_char;
           break;
         }
       }
-      if (type == SuppressionTypeCount) {
+      if (type == suppression_types_num_) {
         Printf("%s: failed to parse suppressions\n", SanitizerToolName);
         Die();
       }
       Suppression s;
-      s.type = static_cast<SuppressionType>(type);
+      s.type = suppression_types_[type];
       s.templ = (char*)InternalAlloc(end2 - line + 1);
       internal_memcpy(s.templ, line, end2 - line);
       s.templ[end2 - line] = 0;
       s.hit_count = 0;
       s.weight = 0;
       suppressions_.push_back(s);
-      has_suppresson_type_[s.type] = true;
+      has_suppression_type_[type] = true;
     }
     if (end[0] == 0)
       break;
@@ -128,8 +116,12 @@ uptr SuppressionContext::SuppressionCount() const {
   return suppressions_.size();
 }
 
-bool SuppressionContext::HasSuppressionType(SuppressionType type) const {
-  return has_suppresson_type_[type];
+bool SuppressionContext::HasSuppressionType(const char *type) const {
+  for (int i = 0; i < suppression_types_num_; i++) {
+    if (0 == internal_strcmp(type, suppression_types_[i]))
+      return has_suppression_type_[i];
+  }
+  return false;
 }
 
 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
@@ -144,9 +136,4 @@ void SuppressionContext::GetMatched(
       matched->push_back(&suppressions_[i]);
 }
 
-const char *SuppressionTypeString(SuppressionType t) {
-  CHECK(t < SuppressionTypeCount);
-  return kTypeStrings[t];
-}
-
 }  // namespace __sanitizer
index afb3150..02dbf6f 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Suppression parsing/matching code shared between TSan and LSan.
+// Suppression parsing/matching code.
 //
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_SUPPRESSIONS_H
 
 namespace __sanitizer {
 
-enum SuppressionType {
-  SuppressionNone,
-  SuppressionRace,
-  SuppressionMutex,
-  SuppressionThread,
-  SuppressionSignal,
-  SuppressionLeak,
-  SuppressionLib,
-  SuppressionDeadlock,
-  SuppressionVptrCheck,
-  SuppressionInterceptorName,
-  SuppressionInterceptorViaFunction,
-  SuppressionInterceptorViaLibrary,
-  SuppressionTypeCount
-};
-
 struct Suppression {
-  SuppressionType type;
+  const char *type;
   char *templ;
   unsigned hit_count;
   uptr weight;
@@ -43,31 +27,29 @@ struct Suppression {
 
 class SuppressionContext {
  public:
+  // Create new SuppressionContext capable of parsing given suppression types.
+  SuppressionContext(const char *supprression_types[],
+                     int suppression_types_num);
+
+  void ParseFromFile(const char *filename);
   void Parse(const char *str);
-  bool Match(const char* str, SuppressionType type, Suppression **s);
+
+  bool Match(const char *str, const char *type, Suppression **s);
   uptr SuppressionCount() const;
-  bool HasSuppressionType(SuppressionType type) const;
+  bool HasSuppressionType(const char *type) const;
   const Suppression *SuppressionAt(uptr i) const;
   void GetMatched(InternalMmapVector<Suppression *> *matched);
 
-  // Create a SuppressionContext singleton if it hasn't been created earlier.
-  // Not thread safe. Must be called early during initialization (but after
-  // runtime flags are parsed).
-  static void InitIfNecessary();
-  // Returns a SuppressionContext singleton.
-  static SuppressionContext *Get();
-
  private:
-  SuppressionContext();
+  static const int kMaxSuppressionTypes = 16;
+  const char **const suppression_types_;
+  const int suppression_types_num_;
+
   InternalMmapVector<Suppression> suppressions_;
-  bool has_suppresson_type_[SuppressionTypeCount];
+  bool has_suppression_type_[kMaxSuppressionTypes];
   bool can_parse_;
-
-  friend class SuppressionContextTest;
 };
 
-const char *SuppressionTypeString(SuppressionType t);
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_SUPPRESSIONS_H
index 0699243..e8c30d0 100644 (file)
@@ -58,117 +58,77 @@ TEST(Suppressions, Match) {
   EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
 }
 
-TEST(Suppressions, TypeStrings) {
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionNone), "none"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionRace), "race"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionMutex), "mutex"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
-                         "called_from_lib"));
-  CHECK(
-      !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
-                         "vptr_check"));
-  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionInterceptorName),
-                         "interceptor_name"));
-  CHECK(
-      !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaFunction),
-                       "interceptor_via_fun"));
-  CHECK(
-      !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaLibrary),
-                       "interceptor_via_lib"));
-  // Ensure this test is up-to-date when suppression types are added.
-  CHECK_EQ(12, SuppressionTypeCount);
-}
+static const char *kTestSuppressionTypes[] = {"race", "thread", "mutex",
+                                              "signal"};
 
 class SuppressionContextTest : public ::testing::Test {
  public:
-  virtual void SetUp() { ctx_ = new(placeholder_) SuppressionContext; }
-  virtual void TearDown() { ctx_->~SuppressionContext(); }
+  SuppressionContextTest()
+      : ctx_(kTestSuppressionTypes, ARRAY_SIZE(kTestSuppressionTypes)) {}
 
  protected:
-  InternalMmapVector<Suppression> *Suppressions() {
-    return &ctx_->suppressions_;
+  SuppressionContext ctx_;
+
+  void CheckSuppressions(unsigned count, std::vector<const char *> types,
+                         std::vector<const char *> templs) const {
+    EXPECT_EQ(count, ctx_.SuppressionCount());
+    for (unsigned i = 0; i < count; i++) {
+      const Suppression *s = ctx_.SuppressionAt(i);
+      EXPECT_STREQ(types[i], s->type);
+      EXPECT_STREQ(templs[i], s->templ);
+    }
   }
-  SuppressionContext *ctx_;
-  ALIGNED(64) char placeholder_[sizeof(SuppressionContext)];
 };
 
 TEST_F(SuppressionContextTest, Parse) {
-  ctx_->Parse(
-    "race:foo\n"
-    "  race:bar\n"  // NOLINT
-    "race:baz   \n"  // NOLINT
-    "# a comment\n"
-    "race:quz\n"
-  );  // NOLINT
-  EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
-  EXPECT_EQ((*Suppressions())[3].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
-  EXPECT_EQ((*Suppressions())[2].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
-  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
-  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+  ctx_.Parse("race:foo\n"
+             "         race:bar\n"  // NOLINT
+             "race:baz  \n" // NOLINT
+             "# a comment\n"
+             "race:quz\n"); // NOLINT
+  CheckSuppressions(4, {"race", "race", "race", "race"},
+                    {"foo", "bar", "baz", "quz"});
 }
 
 TEST_F(SuppressionContextTest, Parse2) {
-  ctx_->Parse(
+  ctx_.Parse(
     "          # first line comment\n"  // NOLINT
     "  race:bar        \n"  // NOLINT
     "race:baz* *baz\n"
     "# a comment\n"
     "# last line comment\n"
   );  // NOLINT
-  EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
-  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "baz* *baz"));
-  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "bar"));
+  CheckSuppressions(2, {"race", "race"}, {"bar", "baz* *baz"});
 }
 
 TEST_F(SuppressionContextTest, Parse3) {
-  ctx_->Parse(
+  ctx_.Parse(
     "# last suppression w/o line-feed\n"
     "race:foo\n"
     "race:bar"
   );  // NOLINT
-  EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
-  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
-  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+  CheckSuppressions(2, {"race", "race"}, {"foo", "bar"});
 }
 
 TEST_F(SuppressionContextTest, ParseType) {
-  ctx_->Parse(
+  ctx_.Parse(
     "race:foo\n"
     "thread:bar\n"
     "mutex:baz\n"
     "signal:quz\n"
   );  // NOLINT
-  EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
-  EXPECT_EQ((*Suppressions())[3].type, SuppressionSignal);
-  EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
-  EXPECT_EQ((*Suppressions())[2].type, SuppressionMutex);
-  EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
-  EXPECT_EQ((*Suppressions())[1].type, SuppressionThread);
-  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
-  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
-  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+  CheckSuppressions(4, {"race", "thread", "mutex", "signal"},
+                    {"foo", "bar", "baz", "quz"});
 }
 
 TEST_F(SuppressionContextTest, HasSuppressionType) {
-  ctx_->Parse(
+  ctx_.Parse(
     "race:foo\n"
     "thread:bar\n");
-  EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionRace));
-  EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionThread));
-  EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionMutex));
-  EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionSignal));
+  EXPECT_TRUE(ctx_.HasSuppressionType("race"));
+  EXPECT_TRUE(ctx_.HasSuppressionType("thread"));
+  EXPECT_FALSE(ctx_.HasSuppressionType("mutex"));
+  EXPECT_FALSE(ctx_.HasSuppressionType("signal"));
 }
 
 }  // namespace __sanitizer
index d15b722..e499468 100644 (file)
@@ -76,3 +76,4 @@ TSAN_FLAG(int, io_sync, 1,
           "2 - global synchronization of all IO operations.")
 TSAN_FLAG(bool, die_after_fork, true,
           "Die after multi-threaded fork if the child creates new threads.")
+TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
index de469ce..31ff7d5 100644 (file)
@@ -182,11 +182,11 @@ static LibIgnore *libignore() {
 }
 
 void InitializeLibIgnore() {
-  const SuppressionContext &supp = *SuppressionContext::Get();
+  const SuppressionContext &supp = *Suppressions();
   const uptr n = supp.SuppressionCount();
   for (uptr i = 0; i < n; i++) {
     const Suppression *s = supp.SuppressionAt(i);
-    if (s->type == SuppressionLib)
+    if (0 == internal_strcmp(s->type, kSuppressionLib))
       libignore()->AddIgnoredLibrary(s->templ);
   }
   libignore()->OnLibraryLoaded(0);
index 299fc80..5413f04 100644 (file)
@@ -41,63 +41,74 @@ extern "C" const char *WEAK __tsan_default_suppressions() {
 
 namespace __tsan {
 
-static bool suppressions_inited = false;
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char *kSuppressionTypes[] = {
+    kSuppressionRace,   kSuppressionMutex, kSuppressionThread,
+    kSuppressionSignal, kSuppressionLib,   kSuppressionDeadlock};
 
 void InitializeSuppressions() {
-  CHECK(!suppressions_inited);
-  SuppressionContext::InitIfNecessary();
+  CHECK_EQ(nullptr, suppression_ctx);
+  suppression_ctx = new (suppression_placeholder) // NOLINT
+      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+  suppression_ctx->ParseFromFile(flags()->suppressions);
 #ifndef SANITIZER_GO
-  SuppressionContext::Get()->Parse(__tsan_default_suppressions());
-  SuppressionContext::Get()->Parse(std_suppressions);
+  suppression_ctx->Parse(__tsan_default_suppressions());
+  suppression_ctx->Parse(std_suppressions);
 #endif
-  suppressions_inited = true;
 }
 
-SuppressionType conv(ReportType typ) {
+SuppressionContext *Suppressions() {
+  CHECK(suppression_ctx);
+  return suppression_ctx;
+}
+
+static const char *conv(ReportType typ) {
   if (typ == ReportTypeRace)
-    return SuppressionRace;
+    return kSuppressionRace;
   else if (typ == ReportTypeVptrRace)
-    return SuppressionRace;
+    return kSuppressionRace;
   else if (typ == ReportTypeUseAfterFree)
-    return SuppressionRace;
+    return kSuppressionRace;
   else if (typ == ReportTypeVptrUseAfterFree)
-    return SuppressionRace;
+    return kSuppressionRace;
   else if (typ == ReportTypeThreadLeak)
-    return SuppressionThread;
+    return kSuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
-    return SuppressionMutex;
+    return kSuppressionMutex;
   else if (typ == ReportTypeMutexDoubleLock)
-    return SuppressionMutex;
+    return kSuppressionMutex;
   else if (typ == ReportTypeMutexBadUnlock)
-    return SuppressionMutex;
+    return kSuppressionMutex;
   else if (typ == ReportTypeMutexBadReadLock)
-    return SuppressionMutex;
+    return kSuppressionMutex;
   else if (typ == ReportTypeMutexBadReadUnlock)
-    return SuppressionMutex;
+    return kSuppressionMutex;
   else if (typ == ReportTypeSignalUnsafe)
-    return SuppressionSignal;
+    return kSuppressionSignal;
   else if (typ == ReportTypeErrnoInSignal)
-    return SuppressionNone;
+    return kSuppressionNone;
   else if (typ == ReportTypeDeadlock)
-    return SuppressionDeadlock;
+    return kSuppressionDeadlock;
   Printf("ThreadSanitizer: unknown report type %d\n", typ),
   Die();
 }
 
 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
-  if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 ||
+  CHECK(suppression_ctx);
+  if (!suppression_ctx->SuppressionCount() || stack == 0 ||
       !stack->suppressable)
     return 0;
-  SuppressionType stype = conv(typ);
-  if (stype == SuppressionNone)
+  const char *stype = conv(typ);
+  if (0 == internal_strcmp(stype, kSuppressionNone))
     return 0;
   Suppression *s;
   for (const SymbolizedStack *frame = stack->frames; frame;
        frame = frame->next) {
     const AddressInfo &info = frame->info;
-    if (SuppressionContext::Get()->Match(info.function, stype, &s) ||
-        SuppressionContext::Get()->Match(info.file, stype, &s) ||
-        SuppressionContext::Get()->Match(info.module, stype, &s)) {
+    if (suppression_ctx->Match(info.function, stype, &s) ||
+        suppression_ctx->Match(info.file, stype, &s) ||
+        suppression_ctx->Match(info.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
@@ -108,16 +119,17 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
 }
 
 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
-  if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 ||
+  CHECK(suppression_ctx);
+  if (!suppression_ctx->SuppressionCount() || loc == 0 ||
       loc->type != ReportLocationGlobal || !loc->suppressable)
     return 0;
-  SuppressionType stype = conv(typ);
-  if (stype == SuppressionNone)
+  const char *stype = conv(typ);
+  if (0 == internal_strcmp(stype, kSuppressionNone))
     return 0;
   Suppression *s;
   const DataInfo &global = loc->global;
-  if (SuppressionContext::Get()->Match(global.name, stype, &s) ||
-      SuppressionContext::Get()->Match(global.module, stype, &s)) {
+  if (suppression_ctx->Match(global.name, stype, &s) ||
+      suppression_ctx->Match(global.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
@@ -128,7 +140,8 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
 
 void PrintMatchedSuppressions() {
   InternalMmapVector<Suppression *> matched(1);
-  SuppressionContext::Get()->GetMatched(&matched);
+  CHECK(suppression_ctx);
+  suppression_ctx->GetMatched(&matched);
   if (!matched.size())
     return;
   int hit_count = 0;
@@ -137,8 +150,8 @@ void PrintMatchedSuppressions() {
   Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
          (int)internal_getpid());
   for (uptr i = 0; i < matched.size(); i++) {
-    Printf("%d %s:%s\n", matched[i]->hit_count,
-           SuppressionTypeString(matched[i]->type), matched[i]->templ);
+    Printf("%d %s:%s\n", matched[i]->hit_count, matched[i]->type,
+           matched[i]->templ);
   }
 }
 }  // namespace __tsan
index c618b3d..e6d279c 100644 (file)
 
 namespace __tsan {
 
+const char kSuppressionNone[] = "none";
+const char kSuppressionRace[] = "race";
+const char kSuppressionMutex[] = "mutex";
+const char kSuppressionThread[] = "thread";
+const char kSuppressionSignal[] = "signal";
+const char kSuppressionLib[] = "called_from_lib";
+const char kSuppressionDeadlock[] = "deadlock";
+
 void InitializeSuppressions();
+SuppressionContext *Suppressions();
 void PrintMatchedSuppressions();
 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
index 57890f7..4f2a2a9 100644 (file)
 #include "ubsan_diag.h"
 #include "ubsan_init.h"
 #include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_stacktrace_printer.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include <stdio.h>
 
@@ -333,11 +335,24 @@ ScopedReport::~ScopedReport() {
     Die();
 }
 
-bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) {
-  Suppression *s;
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kVptrCheck[] = "vptr_check";
+static const char *kSuppressionTypes[] = { kVptrCheck };
+
+void __ubsan::InitializeSuppressions() {
+  CHECK_EQ(nullptr, suppression_ctx);
+  suppression_ctx = new (suppression_placeholder) // NOLINT
+      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+  suppression_ctx->ParseFromFile(flags()->suppressions);
+}
+
+bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
   // If .preinit_array is not used, it is possible that the UBSan runtime is not
   // initialized.
   if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
     InitIfNecessary();
-  return SuppressionContext::Get()->Match(Str, Type, &s);
+  CHECK(suppression_ctx);
+  Suppression *s;
+  return suppression_ctx->Match(TypeName, kVptrCheck, &s);
 }
index e1c6571..44dca90 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "ubsan_value.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
-#include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
 namespace __ubsan {
@@ -236,7 +235,8 @@ public:
   ~ScopedReport();
 };
 
-bool MatchSuppression(const char *Str, SuppressionType Type);
+void InitializeSuppressions();
+bool IsVptrCheckSuppressed(const char *TypeName);
 
 } // namespace __ubsan
 
index 3260e8e..9ca31d1 100644 (file)
@@ -21,4 +21,5 @@ UBSAN_FLAG(bool, halt_on_error, false,
            "Crash the program after printing the first error report")
 UBSAN_FLAG(bool, print_stacktrace, false,
            "Include full stacktrace into an error report")
+UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
 
index 5704c1e..4718e6e 100644 (file)
@@ -36,8 +36,7 @@ static void HandleDynamicTypeCacheMiss(
 
   // Check if error report should be suppressed.
   DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
-  if (DTI.isValid() &&
-      MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck))
+  if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
     return;
 
   SourceLocation Loc = Data->Loc.acquire();
index 48fa492..219273d 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_diag.h"
 #include "ubsan_init.h"
 #include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_mutex.h"
-#include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
 using namespace __ubsan;
@@ -43,7 +43,7 @@ void __ubsan::InitIfNecessary() {
   }
   // Initialize UBSan-specific flags.
   InitializeFlags(standalone);
-  SuppressionContext::InitIfNecessary();
+  InitializeSuppressions();
   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
   ubsan_inited = true;
 }
index dc408d3..1f8ee02 100644 (file)
 // RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
 
 // RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mS 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fS 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cS 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mV 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fV 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cV 2>&1
-// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t oU 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mS 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fS 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cS 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mV 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fV 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cV 2>&1
+// RUN: UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t oU 2>&1
 
 // RUN: echo "vptr_check:S" > %t.loc-supp
-// RUN: ASAN_OPTIONS="suppressions='%t.loc-supp'" UBSAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
+// RUN: UBSAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
 
 // FIXME: This test produces linker errors on Darwin.
 // XFAIL: darwin