diff options
-rw-r--r-- | lib/asan/asan_flags.inc | 1 | ||||
-rw-r--r-- | lib/asan/asan_suppressions.cc | 40 | ||||
-rw-r--r-- | lib/lsan/lsan_common.cc | 29 | ||||
-rw-r--r-- | lib/lsan/lsan_flags.inc | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.inc | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_suppressions.cc | 87 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_suppressions.h | 48 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_suppressions_test.cc | 106 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_flags.inc | 1 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_suppressions.cc | 81 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_suppressions.h | 9 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.cc | 21 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.h | 4 | ||||
-rw-r--r-- | lib/ubsan/ubsan_flags.inc | 1 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.cc | 3 | ||||
-rw-r--r-- | lib/ubsan/ubsan_init.cc | 4 | ||||
-rw-r--r-- | test/ubsan/TestCases/TypeCheck/vptr.cpp | 16 |
18 files changed, 220 insertions, 237 deletions
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index ec9d41980..53a8a4039 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -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.") diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc index ef554716f..62198aec6 100644 --- a/lib/asan/asan_suppressions.cc +++ b/lib/asan/asan_suppressions.cc @@ -15,57 +15,62 @@ #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; } diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 6dafb8484..b9e2a1104 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -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; } } diff --git a/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc index 7f00acbf9..b19b3452b 100644 --- a/lib/lsan/lsan_flags.inc +++ b/lib/lsan/lsan_flags.inc @@ -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.") diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index e8c8a8753..58f7f3722 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -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( diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index ec4789c90..2b697e955 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// Suppression parsing/matching code shared between TSan and LSan. +// Suppression parsing/matching code. // //===----------------------------------------------------------------------===// @@ -21,55 +21,43 @@ 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 diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h index afb3150fe..02dbf6f96 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.h +++ b/lib/sanitizer_common/sanitizer_suppressions.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// Suppression parsing/matching code shared between TSan and LSan. +// Suppression parsing/matching code. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_SUPPRESSIONS_H @@ -18,24 +18,8 @@ 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 diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc index 069924328..e8c30d07e 100644 --- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc @@ -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 diff --git a/lib/tsan/rtl/tsan_flags.inc b/lib/tsan/rtl/tsan_flags.inc index d15b722ee..e4994685f 100644 --- a/lib/tsan/rtl/tsan_flags.inc +++ b/lib/tsan/rtl/tsan_flags.inc @@ -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.") diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index de469ce64..31ff7d56a 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -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); diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc index 299fc80fd..5413f04af 100644 --- a/lib/tsan/rtl/tsan_suppressions.cc +++ b/lib/tsan/rtl/tsan_suppressions.cc @@ -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 diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h index c618b3db4..e6d279c33 100644 --- a/lib/tsan/rtl/tsan_suppressions.h +++ b/lib/tsan/rtl/tsan_suppressions.h @@ -18,7 +18,16 @@ 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); diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index 57890f711..4f2a2a9f3 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -14,9 +14,11 @@ #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); } diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index e1c6571f5..44dca90b7 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -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 diff --git a/lib/ubsan/ubsan_flags.inc b/lib/ubsan/ubsan_flags.inc index 3260e8e13..9ca31d13a 100644 --- a/lib/ubsan/ubsan_flags.inc +++ b/lib/ubsan/ubsan_flags.inc @@ -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.") diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index 5704c1e63..4718e6eac 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -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(); diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index 48fa49248..219273d51 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -11,12 +11,12 @@ // //===----------------------------------------------------------------------===// +#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; } diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index dc408d39a..1f8ee0264 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -12,16 +12,16 @@ // 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 |