Index: lib/sanitizer_common/sanitizer_suppressions.h =================================================================== --- lib/sanitizer_common/sanitizer_suppressions.h +++ lib/sanitizer_common/sanitizer_suppressions.h @@ -27,6 +27,7 @@ SuppressionLeak, SuppressionLib, SuppressionDeadlock, + SuppressionUBSanVptr, SuppressionTypeCount }; Index: lib/sanitizer_common/sanitizer_suppressions.cc =================================================================== --- lib/sanitizer_common/sanitizer_suppressions.cc +++ lib/sanitizer_common/sanitizer_suppressions.cc @@ -20,8 +20,9 @@ namespace __sanitizer { static const char *const kTypeStrings[SuppressionTypeCount] = { - "none", "race", "mutex", "thread", - "signal", "leak", "called_from_lib", "deadlock"}; + "none", "race", "mutex", "thread", + "signal", "leak", "called_from_lib", "deadlock", + "ubsan_vptr"}; bool TemplateMatch(char *templ, const char *str) { if (str == 0 || str[0] == 0) Index: lib/sanitizer_common/tests/sanitizer_suppressions_test.cc =================================================================== --- lib/sanitizer_common/tests/sanitizer_suppressions_test.cc +++ lib/sanitizer_common/tests/sanitizer_suppressions_test.cc @@ -70,7 +70,7 @@ CHECK( !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock")); // Ensure this test is up-to-date when suppression types are added. - CHECK_EQ(SuppressionTypeCount, 8); + CHECK_EQ(SuppressionTypeCount, 9); } class SuppressionContextTest : public ::testing::Test { Index: lib/ubsan/ubsan_flags.h =================================================================== --- lib/ubsan/ubsan_flags.h +++ lib/ubsan/ubsan_flags.h @@ -17,6 +17,7 @@ struct Flags { bool print_stacktrace; + const char* suppressions; }; extern Flags ubsan_flags; Index: lib/ubsan/ubsan_flags.cc =================================================================== --- lib/ubsan/ubsan_flags.cc +++ lib/ubsan/ubsan_flags.cc @@ -23,11 +23,14 @@ Flags *f = flags(); // Default values. f->print_stacktrace = false; + f->suppressions = 0; const char *options = GetEnv("UBSAN_OPTIONS"); if (options) { ParseFlag(options, &f->print_stacktrace, "print_stacktrace", "Include full stacktrace into an error report"); + ParseFlag(options, &f->suppressions, "suppressions", + "Suppression format filename to suppress an error report"); } } Index: lib/ubsan/ubsan_handlers_cxx.cc =================================================================== --- lib/ubsan/ubsan_handlers_cxx.cc +++ lib/ubsan/ubsan_handlers_cxx.cc @@ -18,6 +18,7 @@ #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_suppressions.h" using namespace __sanitizer; using namespace __ubsan; @@ -26,6 +27,8 @@ extern const char *TypeCheckKinds[]; } +extern SuppressionContext *suppression_ctx; + static void HandleDynamicTypeCacheMiss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, bool Abort) { @@ -37,12 +40,19 @@ if (Loc.isDisabled()) return; + DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); + + // Suppress an error report if it is specified. + Suppression *s; + if (suppression_ctx && + suppression_ctx->Match(DTI.getMostDerivedTypeName(), SuppressionUBSanVptr, &s)) + return; + Diag(Loc, DL_Error, "%0 address %1 which does not point to an object of type %2") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; // If possible, say what type it actually points to. - DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); if (!DTI.isValid()) Diag(Pointer, DL_Note, "object has invalid vptr") << MangledName(DTI.getMostDerivedTypeName()) Index: lib/ubsan/ubsan_init.cc =================================================================== --- lib/ubsan/ubsan_init.cc +++ lib/ubsan/ubsan_init.cc @@ -18,9 +18,34 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_symbolizer.h" +#include "sanitizer_common/sanitizer_suppressions.h" +#include "sanitizer_common/sanitizer_placement_new.h" using namespace __ubsan; +SuppressionContext *suppression_ctx; + +static void InitializeSuppressions() { + CHECK(!suppression_ctx); + + if (!flags()->suppressions) + return; + + ALIGNED(64) static char placeholder[sizeof(SuppressionContext)]; + suppression_ctx = new(placeholder) SuppressionContext; + + char *suppressions_from_file; + uptr buffer_size; + if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file, + &buffer_size, 1 << 26 /* max_len */)) + suppression_ctx->Parse(suppressions_from_file); + if (flags()->suppressions[0] && !buffer_size) { + Printf("UBSan: failed to read suppressions file '%s'\n", + flags()->suppressions); + Die(); + } +} + static bool ubsan_inited; void __ubsan::InitIfNecessary() { @@ -47,6 +72,7 @@ } // Initialize UBSan-specific flags. InitializeFlags(); + InitializeSuppressions(); ubsan_inited = true; } Index: test/ubsan/TestCases/TypeCheck/vptr.cpp =================================================================== --- test/ubsan/TestCases/TypeCheck/vptr.cpp +++ test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -11,6 +11,15 @@ // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace +// RUN: (echo "ubsan_vptr:S"; echo "ubsan_vptr:T"; echo "ubsan_vptr:U") > %t.supp +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t mS 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t fS 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t cS 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t mV 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t fV 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t cV 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS +// RUN: (echo " " ; UBSAN_OPTIONS=suppressions=%t.supp %run %t oU 2>&1) | FileCheck %s --check-prefix=CHECK-SUPPRESS + // FIXME: This test produces linker errors on Darwin. // XFAIL: darwin @@ -121,3 +130,4 @@ return 0; } } +// CHECK-SUPPRESS-NOT: runtime error: