forked from OSchip/llvm-project
[UBSan] Allow to suppress reports from vptr checker for specified types.
Based on http://reviews.llvm.org/D4702 by Byoungyoung Lee! llvm-svn: 214833
This commit is contained in:
parent
4dbf44b9d8
commit
ff24fd2516
|
@ -22,8 +22,8 @@
|
|||
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", "vptr_check"};
|
||||
|
||||
bool TemplateMatch(char *templ, const char *str) {
|
||||
if (str == 0 || str[0] == 0)
|
||||
|
|
|
@ -27,6 +27,7 @@ enum SuppressionType {
|
|||
SuppressionLeak,
|
||||
SuppressionLib,
|
||||
SuppressionDeadlock,
|
||||
SuppressionVptrCheck,
|
||||
SuppressionTypeCount
|
||||
};
|
||||
|
||||
|
|
|
@ -66,11 +66,13 @@ TEST(Suppressions, TypeStrings) {
|
|||
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
|
||||
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
|
||||
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
|
||||
"called_from_lib"));
|
||||
"called_from_lib"));
|
||||
CHECK(
|
||||
!internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
|
||||
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
|
||||
"vptr_check"));
|
||||
// Ensure this test is up-to-date when suppression types are added.
|
||||
CHECK_EQ(SuppressionTypeCount, 8);
|
||||
CHECK_EQ(9, SuppressionTypeCount);
|
||||
}
|
||||
|
||||
class SuppressionContextTest : public ::testing::Test {
|
||||
|
|
|
@ -312,3 +312,12 @@ ScopedReport::~ScopedReport() {
|
|||
if (DieAfterReport)
|
||||
Die();
|
||||
}
|
||||
|
||||
bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) {
|
||||
Suppression *s;
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "ubsan_value.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_suppressions.h"
|
||||
|
||||
namespace __ubsan {
|
||||
|
||||
|
@ -218,6 +219,8 @@ public:
|
|||
~ScopedReport();
|
||||
};
|
||||
|
||||
bool MatchSuppression(const char *Str, SuppressionType Type);
|
||||
|
||||
} // namespace __ubsan
|
||||
|
||||
#endif // UBSAN_DIAG_H
|
||||
|
|
|
@ -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;
|
||||
|
@ -33,6 +34,12 @@ static void HandleDynamicTypeCacheMiss(
|
|||
// Just a cache miss. The type matches after all.
|
||||
return;
|
||||
|
||||
// Check if error report should be suppressed.
|
||||
DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
|
||||
if (DTI.isValid() &&
|
||||
MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck))
|
||||
return;
|
||||
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
@ -44,23 +51,23 @@ static void HandleDynamicTypeCacheMiss(
|
|||
<< 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())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
|
||||
<< MangledName(DTI.getMostDerivedTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
|
||||
else if (!DTI.getOffset())
|
||||
Diag(Pointer, DL_Note, "object is of type %0")
|
||||
<< MangledName(DTI.getMostDerivedTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
|
||||
<< MangledName(DTI.getMostDerivedTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
|
||||
else
|
||||
// FIXME: Find the type at the specified offset, and include that
|
||||
// in the note.
|
||||
Diag(Pointer - DTI.getOffset(), DL_Note,
|
||||
"object is base class subobject at offset %0 within object of type %1")
|
||||
<< DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
|
||||
<< MangledName(DTI.getSubobjectTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");
|
||||
<< DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
|
||||
<< MangledName(DTI.getSubobjectTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr),
|
||||
"vptr for %2 base class of %1");
|
||||
|
||||
MaybePrintStackTrace(pc, bp);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#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;
|
||||
|
@ -42,6 +43,7 @@ void __ubsan::InitIfNecessary() {
|
|||
}
|
||||
// Initialize UBSan-specific flags.
|
||||
InitializeFlags();
|
||||
SuppressionContext::InitIfNecessary();
|
||||
ubsan_inited = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,19 @@
|
|||
// 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: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t
|
||||
// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t mS 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t fS 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t cS 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t mV 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t fV 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t cV 2>&1
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.supp" UBSAN_OPTIONS=suppressions=%t.supp %run %t oU 2>&1
|
||||
|
||||
// RUN: echo "vptr_check:S" > %t.loc-supp
|
||||
// RUN: ASAN_OPTIONS="$ASAN_OPTIONS suppressions=%t.loc-supp" UBSAN_OPTIONS=suppressions=%t.loc-supp not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
|
||||
|
||||
// FIXME: This test produces linker errors on Darwin.
|
||||
// XFAIL: darwin
|
||||
|
||||
|
@ -31,6 +44,8 @@ struct T : S {
|
|||
|
||||
struct U : S, T { virtual int v() { return 2; } };
|
||||
|
||||
struct V : S {};
|
||||
|
||||
// Make p global so that lsan does not complain.
|
||||
T *p = 0;
|
||||
|
||||
|
@ -84,6 +99,19 @@ int access_p(T *p, char type) {
|
|||
{T &r = *p;}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Check that the first iteration ("S") succeeds, while the second ("V") fails.
|
||||
p = reinterpret_cast<T*>((i == 0) ? new S : new V);
|
||||
// CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:7: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
|
||||
// CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
|
||||
// CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
|
||||
// CHECK-LOC-SUPPRESS-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
|
||||
// CHECK-LOC-SUPPRESS-NEXT: {{^ vptr for 'V'}}
|
||||
p->g();
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'm':
|
||||
// CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
|
||||
// CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
|
||||
|
|
Loading…
Reference in New Issue