[compiler-rt] r256018 - [UBSan] Implement runtime suppressions (PR25066).
Alexey Samsonov via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 18 11:56:42 PST 2015
Author: samsonov
Date: Fri Dec 18 13:56:42 2015
New Revision: 256018
URL: http://llvm.org/viewvc/llvm-project?rev=256018&view=rev
Log:
[UBSan] Implement runtime suppressions (PR25066).
Summary:
Add the ability to suppress UBSan reports for files/functions/modules
at runtime. The user can now pass UBSAN_OPTIONS=suppressions=supp.txt
with the contents of the form:
signed-integer-overflow:file-with-known-overflow.cpp
alignment:function_doing_unaligned_access
vptr:shared_object_with_vptr_failures.so
Suppression categories match the arguments passed to -fsanitize=
flag (although, see below). There is no overhead if suppressions are
not provided. Otherwise there is extra overhead for symbolization.
Limitations:
1) sometimes suppressions need debug info / symbol table to function
properly (although sometimes frontend generates enough info to
do the match).
2) it's only possible to suppress recoverable UB kinds - if you've
built the code with -fno-sanitize-recover=undefined, suppressions
will not work.
3) categories are fine-grained check kinds, not groups like "undefined"
or "integer", so you can't write "undefined:file_with_ub.cc".
Reviewers: rsmith, kcc
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D15363
Added:
compiler-rt/trunk/test/ubsan/TestCases/Integer/suppressions.cpp
Modified:
compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h
compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
compiler-rt/trunk/lib/ubsan/ubsan_diag.h
compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h?rev=256018&r1=256017&r2=256018&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h Fri Dec 18 13:56:42 2015
@@ -43,7 +43,7 @@ class SuppressionContext {
void GetMatched(InternalMmapVector<Suppression *> *matched);
private:
- static const int kMaxSuppressionTypes = 16;
+ static const int kMaxSuppressionTypes = 32;
const char **const suppression_types_;
const int suppression_types_num_;
Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=256018&r1=256017&r2=256018&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Fri Dec 18 13:56:42 2015
@@ -54,6 +54,17 @@ static const char *ConvertTypeToString(E
UNREACHABLE("unknown ErrorType!");
}
+static const char *ConvertTypeToFlagName(ErrorType Type) {
+ switch (Type) {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
+ case ErrorType::Name: \
+ return FSanitizeFlagName;
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ }
+ UNREACHABLE("unknown ErrorType!");
+}
+
static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
if (!common_flags()->print_summary)
return;
@@ -372,7 +383,12 @@ ScopedReport::~ScopedReport() {
ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kVptrCheck[] = "vptr_check";
-static const char *kSuppressionTypes[] = { kVptrCheck };
+static const char *kSuppressionTypes[] = {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ kVptrCheck,
+};
void __ubsan::InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
@@ -388,4 +404,28 @@ bool __ubsan::IsVptrCheckSuppressed(cons
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
}
+bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) {
+ InitAsStandaloneIfNecessary();
+ CHECK(suppression_ctx);
+ const char *SuppType = ConvertTypeToFlagName(ET);
+ // Fast path: don't symbolize PC if there is no suppressions for given UB
+ // type.
+ if (!suppression_ctx->HasSuppressionType(SuppType))
+ return false;
+ Suppression *s = nullptr;
+ // Suppress by file name known to runtime.
+ if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s))
+ return true;
+ // Suppress by module name.
+ if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) {
+ if (suppression_ctx->Match(Module, SuppType, &s))
+ return true;
+ }
+ // Suppress by function or source file name from debug info.
+ SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC));
+ const AddressInfo &AI = Stack.get()->info;
+ return suppression_ctx->Match(AI.function, SuppType, &s) ||
+ suppression_ctx->Match(AI.file, SuppType, &s);
+}
+
#endif // CAN_SANITIZE_UB
Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=256018&r1=256017&r2=256018&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.h Fri Dec 18 13:56:42 2015
@@ -225,7 +225,7 @@ enum class ErrorType {
#undef UBSAN_CHECK
};
-bool ignoreReport(SourceLocation SLoc, ReportOptions Opts);
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
#define GET_REPORT_OPTIONS(unrecoverable_handler) \
GET_CALLER_PC_BP; \
@@ -246,6 +246,9 @@ public:
void InitializeSuppressions();
bool IsVptrCheckSuppressed(const char *TypeName);
+// Sometimes UBSan runtime can know filename from handlers arguments, even if
+// debug info is missing.
+bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
} // namespace __ubsan
Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc?rev=256018&r1=256017&r2=256018&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc Fri Dec 18 13:56:42 2015
@@ -22,7 +22,7 @@ using namespace __sanitizer;
using namespace __ubsan;
namespace __ubsan {
-bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
// We are not allowed to skip error report: if we are in unrecoverable
// handler, we have to terminate the program right now, and therefore
// have to print some diagnostic.
@@ -32,7 +32,7 @@ bool ignoreReport(SourceLocation SLoc, R
// thread could have acquired it, but not yet printed the report.
if (Opts.FromUnrecoverableHandler)
return false;
- return SLoc.isDisabled();
+ return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
}
const char *TypeCheckKinds[] = {
@@ -44,15 +44,6 @@ const char *TypeCheckKinds[] = {
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
ReportOptions Opts) {
Location Loc = Data->Loc.acquire();
- // Use the SourceLocation from Data to track deduplication, even if 'invalid'
- if (ignoreReport(Loc.getSourceLocation(), Opts))
- return;
-
- SymbolizedStackHolder FallbackLoc;
- if (Data->Loc.isInvalid()) {
- FallbackLoc.reset(getCallerLocation(Opts.pc));
- Loc = FallbackLoc;
- }
ErrorType ET;
if (!Pointer)
@@ -62,6 +53,17 @@ static void handleTypeMismatchImpl(TypeM
else
ET = ErrorType::InsufficientObjectSize;
+ // Use the SourceLocation from Data to track deduplication, even if it's
+ // invalid.
+ if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
+ return;
+
+ SymbolizedStackHolder FallbackLoc;
+ if (Data->Loc.isInvalid()) {
+ FallbackLoc.reset(getCallerLocation(Opts.pc));
+ Loc = FallbackLoc;
+ }
+
ScopedReport R(Opts, Loc, ET);
switch (ET) {
@@ -106,12 +108,14 @@ static void handleIntegerOverflowImpl(Ov
const char *Operator, T RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- bool IsSigned = Data->Type.isSignedIntegerTy();
- ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
- : ErrorType::UnsignedIntegerOverflow);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "%0 integer overflow: "
"%1 %2 %3 cannot be represented in type %4")
@@ -138,12 +142,14 @@ UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mu
static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- bool IsSigned = Data->Type.isSignedIntegerTy();
- ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
- : ErrorType::UnsignedIntegerOverflow);
+ ScopedReport R(Opts, Loc, ET);
if (IsSigned)
Diag(Loc, DL_Error,
@@ -170,9 +176,6 @@ void __ubsan::__ubsan_handle_negate_over
static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
ValueHandle RHS, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
Value LHSVal(Data->Type, LHS);
Value RHSVal(Data->Type, RHS);
@@ -184,6 +187,9 @@ static void handleDivremOverflowImpl(Ove
else
ET = ErrorType::FloatDivideByZero;
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
ScopedReport R(Opts, Loc, ET);
switch (ET) {
@@ -214,9 +220,6 @@ static void handleShiftOutOfBoundsImpl(S
ValueHandle LHS, ValueHandle RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
Value LHSVal(Data->LHSType, LHS);
Value RHSVal(Data->RHSType, RHS);
@@ -227,6 +230,9 @@ static void handleShiftOutOfBoundsImpl(S
else
ET = ErrorType::InvalidShiftBase;
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
ScopedReport R(Opts, Loc, ET);
if (ET == ErrorType::InvalidShiftExponent) {
@@ -263,10 +269,12 @@ void __ubsan::__ubsan_handle_shift_out_o
static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::OutOfBoundsIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::OutOfBoundsIndex);
+ ScopedReport R(Opts, Loc, ET);
Value IndexVal(Data->IndexType, Index);
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
@@ -313,10 +321,12 @@ void __ubsan::__ubsan_handle_missing_ret
static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::NonPositiveVLAIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::NonPositiveVLAIndex);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "variable length array bound evaluates to "
"non-positive value %0")
@@ -358,6 +368,7 @@ static void handleFloatCastOverflow(void
SymbolizedStackHolder CallerLoc;
Location Loc;
const TypeDescriptor *FromType, *ToType;
+ ErrorType ET = ErrorType::FloatCastOverflow;
if (looksLikeFloatCastOverflowDataV1(DataPtr)) {
auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);
@@ -368,14 +379,14 @@ static void handleFloatCastOverflow(void
} else {
auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);
SourceLocation SLoc = Data->Loc.acquire();
- if (ignoreReport(SLoc, Opts))
+ if (ignoreReport(SLoc, Opts, ET))
return;
Loc = SLoc;
FromType = &Data->FromType;
ToType = &Data->ToType;
}
- ScopedReport R(Opts, Loc, ErrorType::FloatCastOverflow);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"value %0 is outside the range of representable values of type %2")
@@ -396,14 +407,16 @@ void __ubsan::__ubsan_handle_float_cast_
static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
// This check could be more precise if we used different handlers for
// -fsanitize=bool and -fsanitize=enum.
bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'"));
- ScopedReport R(Opts, Loc, IsBool ? ErrorType::InvalidBoolLoad
- : ErrorType::InvalidEnumLoad);
+ ErrorType ET =
+ IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
@@ -426,10 +439,12 @@ static void handleFunctionTypeMismatch(F
ValueHandle Function,
ReportOptions Opts) {
SourceLocation CallLoc = Data->Loc.acquire();
- if (ignoreReport(CallLoc, Opts))
+ ErrorType ET = ErrorType::FunctionTypeMismatch;
+
+ if (ignoreReport(CallLoc, Opts, ET))
return;
- ScopedReport R(Opts, CallLoc, ErrorType::FunctionTypeMismatch);
+ ScopedReport R(Opts, CallLoc, ET);
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
const char *FName = FLoc.get()->info.function;
@@ -458,10 +473,12 @@ void __ubsan::__ubsan_handle_function_ty
static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullReturn;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::InvalidNullReturn);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
@@ -482,10 +499,12 @@ void __ubsan::__ubsan_handle_nonnull_ret
static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullArgument;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::InvalidNullArgument);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
"never be null") << Data->ArgIndex;
@@ -507,10 +526,12 @@ void __ubsan::__ubsan_handle_nonnull_arg
static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::CFIBadType;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::CFIBadType);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
"indirect function call")
Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=256018&r1=256017&r2=256018&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Fri Dec 18 13:56:42 2015
@@ -43,10 +43,11 @@ static bool HandleDynamicTypeCacheMiss(
return false;
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ ErrorType ET = ErrorType::DynamicTypeMismatch;
+ if (ignoreReport(Loc, Opts, ET))
return false;
- ScopedReport R(Opts, Loc, ErrorType::DynamicTypeMismatch);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"%0 address %1 which does not point to an object of type %2")
@@ -89,10 +90,12 @@ void __ubsan::__ubsan_handle_dynamic_typ
static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
+ ErrorType ET = ErrorType::CFIBadType;
- if (ignoreReport(Loc, Opts))
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::CFIBadType);
+
+ ScopedReport R(Opts, Loc, ET);
DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void*)Vtable);
static const char *TypeCheckKinds[] = {
Added: compiler-rt/trunk/test/ubsan/TestCases/Integer/suppressions.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/Integer/suppressions.cpp?rev=256018&view=auto
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/Integer/suppressions.cpp (added)
+++ compiler-rt/trunk/test/ubsan/TestCases/Integer/suppressions.cpp Fri Dec 18 13:56:42 2015
@@ -0,0 +1,33 @@
+// RUN: %clangxx -fsanitize=integer -g0 %s -o %t
+
+// Fails without any suppression.
+// RUN: %env_ubsan_opts=halt_on_error=1 not %run %t 2>&1 | FileCheck %s
+
+// RUN: echo "signed-integer-overflow:%t" > %t.wrong-supp
+// RUN: %env_ubsan_opts=halt_on_error=1:suppressions="%t.wrong-supp" not %run %t 2>&1 | FileCheck %s
+
+// RUN: echo "unsigned-integer-overflow:do_overflow" > %t.func-supp
+// RUN: %env_ubsan_opts=halt_on_error=1:suppressions="%t.func-supp" %run %t
+// RUN: echo "unsigned-integer-overflow:%t" > %t.module-supp
+// RUN: %env_ubsan_opts=halt_on_error=1:suppressions="%t.module-supp" %run %t
+
+// Note: file-level suppressions should work even without debug info.
+// RUN: echo "unsigned-integer-overflow:%s" > %t.file-supp
+// RUN: %env_ubsan_opts=halt_on_error=1:suppressions="%t.file-supp" %run %t
+
+// Suppressions don't work for unrecoverable kinds.
+// RUN: %clangxx -fsanitize=integer -fno-sanitize-recover=integer %s -o %t-norecover
+// RUN: %env_ubsan_opts=halt_on_error=1:suppressions="%t.module-supp" not %run %t-norecover 2>&1 | FileCheck %s
+
+#include <stdint.h>
+
+extern "C" void do_overflow() {
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // CHECK: runtime error: unsigned integer overflow
+}
+
+int main() {
+ do_overflow();
+ return 0;
+}
+
More information about the llvm-commits
mailing list