summaryrefslogtreecommitdiff
path: root/lib/ubsan
diff options
context:
space:
mode:
authorAlexey Samsonov <vonosmas@gmail.com>2015-08-24 23:18:49 +0000
committerAlexey Samsonov <vonosmas@gmail.com>2015-08-24 23:18:49 +0000
commitaef60033031849c68092f304d04bf609b3c269ff (patch)
treeaff383ccd60e135ca8ef2b5879fc6cd315006395 /lib/ubsan
parentb1900f9b3f936a8f84cd42d1aabd899613f32137 (diff)
[UBSan] Add the ability to print more precise error kind in summary line.
Reviewers: rsmith, pcc Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D12215 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@245897 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ubsan')
-rw-r--r--lib/ubsan/ubsan_checks.inc53
-rw-r--r--lib/ubsan/ubsan_diag.cc30
-rw-r--r--lib/ubsan/ubsan_diag.h11
-rw-r--r--lib/ubsan/ubsan_flags.inc3
-rw-r--r--lib/ubsan/ubsan_handlers.cc80
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc4
6 files changed, 139 insertions, 42 deletions
diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc
new file mode 100644
index 000000000..dac479f51
--- /dev/null
+++ b/lib/ubsan/ubsan_checks.inc
@@ -0,0 +1,53 @@
+//===-- ubsan_checks.inc ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// List of checks handled by UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_CHECK
+# error "Define UBSAN_CHECK prior to including this file!"
+#endif
+
+// UBSAN_CHECK(Name, SummaryKind, FlagName)
+// SummaryKind and FlagName should be string literals.
+
+UBSAN_CHECK(GenericUB, "undefined-behavior", "-fsanitize=undefined")
+UBSAN_CHECK(NullPointerUse, "null-pointer-use", "-fsanitize=null")
+UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use",
+ "-fsanitize=alignment")
+UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size",
+ "-fsanitize=object-size")
+UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",
+ "-fsanitize=signed-integer-overflow")
+UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow",
+ "-fsanitize=unsigned-integer-overflow")
+UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
+ "-fsanitize=integer-divide-by-zero")
+UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero",
+ "-fsanitize=float-divide-by-zero")
+UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "-fsanitize=shift-base")
+UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent",
+ "-fsanitize=shift-exponent")
+UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "-fsanitize=bounds")
+UBSAN_CHECK(UnreachableCall, "unreachable-call", "-fsanitize=unreachable")
+UBSAN_CHECK(MissingReturn, "missing-return", "-fsanitize=return")
+UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index",
+ "-fsanitize=vla-bound")
+UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow",
+ "-fsanitize=float-cast-overflow")
+UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "-fsanitize=bool")
+UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "-fsanitize=enum")
+UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch",
+ "-fsanitize=function")
+UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
+ "-fsanitize=returns-nonnull-attribute")
+UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument",
+ "-fsanitize=nonnull-attribute")
+UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "-fsanitize=vptr")
+UBSAN_CHECK(CFIBadType, "cfi-bad-type", "-fsanitize=cfi")
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 3d5042b51..17e973cf6 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -43,10 +43,23 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) {
stack.Print();
}
-static void MaybeReportErrorSummary(Location Loc) {
+static const char *ConvertTypeToString(ErrorType Type) {
+ switch (Type) {
+#define UBSAN_CHECK(Name, SummaryKind, FlagName) \
+ case ErrorType::Name: \
+ return SummaryKind;
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ }
+ UNREACHABLE("unknown ErrorType!");
+}
+
+static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
if (!common_flags()->print_summary)
return;
- const char *ErrorType = "undefined-behavior";
+ if (!flags()->report_error_type)
+ Type = ErrorType::GenericUB;
+ const char *ErrorKind = ConvertTypeToString(Type);
if (Loc.isSourceLocation()) {
SourceLocation SLoc = Loc.getSourceLocation();
if (!SLoc.isInvalid()) {
@@ -55,16 +68,16 @@ static void MaybeReportErrorSummary(Location Loc) {
AI.line = SLoc.getLine();
AI.column = SLoc.getColumn();
AI.function = internal_strdup(""); // Avoid printing ?? as function name.
- ReportErrorSummary(ErrorType, AI);
+ ReportErrorSummary(ErrorKind, AI);
AI.Clear();
return;
}
} else if (Loc.isSymbolizedStack()) {
const AddressInfo &AI = Loc.getSymbolizedStack()->info;
- ReportErrorSummary(ErrorType, AI);
+ ReportErrorSummary(ErrorKind, AI);
return;
}
- ReportErrorSummary(ErrorType);
+ ReportErrorSummary(ErrorKind);
}
namespace {
@@ -341,15 +354,16 @@ Diag::~Diag() {
NumRanges, Args);
}
-ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
- : Opts(Opts), SummaryLoc(SummaryLoc) {
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
+ ErrorType Type)
+ : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {
InitAsStandaloneIfNecessary();
CommonSanitizerReportMutex.Lock();
}
ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
- MaybeReportErrorSummary(SummaryLoc);
+ MaybeReportErrorSummary(SummaryLoc, Type);
CommonSanitizerReportMutex.Unlock();
if (Opts.DieAfterReport || flags()->halt_on_error)
Die();
diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h
index 615a646d9..2aa62eb74 100644
--- a/lib/ubsan/ubsan_diag.h
+++ b/lib/ubsan/ubsan_diag.h
@@ -219,6 +219,12 @@ struct ReportOptions {
uptr bp;
};
+enum class ErrorType {
+#define UBSAN_CHECK(Name, SummaryKind, FlagName) Name,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+};
+
#define GET_REPORT_OPTIONS(die_after_report) \
GET_CALLER_PC_BP; \
ReportOptions Opts = {die_after_report, pc, bp}
@@ -229,9 +235,12 @@ struct ReportOptions {
class ScopedReport {
ReportOptions Opts;
Location SummaryLoc;
+ ErrorType Type;
public:
- ScopedReport(ReportOptions Opts, Location SummaryLoc);
+ ScopedReport(ReportOptions Opts, Location SummaryLoc,
+ ErrorType Type = ErrorType::GenericUB);
+ void setErrorType(ErrorType T) { Type = T; }
~ScopedReport();
};
diff --git a/lib/ubsan/ubsan_flags.inc b/lib/ubsan/ubsan_flags.inc
index 9ca31d13a..d171a98e1 100644
--- a/lib/ubsan/ubsan_flags.inc
+++ b/lib/ubsan/ubsan_flags.inc
@@ -22,4 +22,5 @@ UBSAN_FLAG(bool, halt_on_error, false,
UBSAN_FLAG(bool, print_stacktrace, false,
"Include full stacktrace into an error report")
UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
-
+UBSAN_FLAG(bool, report_error_type, false,
+ "Print specific error type instead of 'undefined-behavior' in summary.")
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 1e8fee355..c175baa46 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -53,18 +53,22 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
ScopedReport R(Opts, Loc);
- if (!Pointer)
+ if (!Pointer) {
+ R.setErrorType(ErrorType::NullPointerUse);
Diag(Loc, DL_Error, "%0 null pointer of type %1")
<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
- else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ } else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) {
+ R.setErrorType(ErrorType::MisalignedPointerUse);
Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
"which requires %2 byte alignment")
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
<< Data->Alignment << Data->Type;
- else
+ } else {
+ R.setErrorType(ErrorType::InsufficientObjectSize);
Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
"for an object of type %2")
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+ }
if (Pointer)
Diag(Pointer, DL_Note, "pointer points here");
}
@@ -90,11 +94,13 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow);
Diag(Loc, DL_Error, "%0 integer overflow: "
"%1 %2 %3 cannot be represented in type %4")
- << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
+ << (IsSigned ? "signed" : "unsigned")
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
}
@@ -119,17 +125,18 @@ static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow);
- if (Data->Type.isSignedIntegerTy())
+ if (IsSigned)
Diag(Loc, DL_Error,
"negation of %0 cannot be represented in type %1; "
"cast to an unsigned type to negate this value to itself")
- << Value(Data->Type, OldVal) << Data->Type;
+ << Value(Data->Type, OldVal) << Data->Type;
else
- Diag(Loc, DL_Error,
- "negation of %0 cannot be represented in type %1")
- << Value(Data->Type, OldVal) << Data->Type;
+ Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1")
+ << Value(Data->Type, OldVal) << Data->Type;
}
void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
@@ -154,12 +161,16 @@ static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
Value LHSVal(Data->Type, LHS);
Value RHSVal(Data->Type, RHS);
- if (RHSVal.isMinusOne())
+ if (RHSVal.isMinusOne()) {
+ R.setErrorType(ErrorType::SignedIntegerOverflow);
Diag(Loc, DL_Error,
"division of %0 by -1 cannot be represented in type %1")
<< LHSVal << Data->Type;
- else
+ } else {
+ R.setErrorType(Data->Type.isIntegerTy() ? ErrorType::IntegerDivideByZero
+ : ErrorType::FloatDivideByZero);
Diag(Loc, DL_Error, "division by zero");
+ }
}
void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
@@ -186,18 +197,23 @@ static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
Value LHSVal(Data->LHSType, LHS);
Value RHSVal(Data->RHSType, RHS);
- if (RHSVal.isNegative())
+ if (RHSVal.isNegative()) {
+ R.setErrorType(ErrorType::InvalidShiftExponent);
Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
- else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
- Diag(Loc, DL_Error,
- "shift exponent %0 is too large for %1-bit type %2")
- << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
- else if (LHSVal.isNegative())
+ } else if (RHSVal.getPositiveIntValue() >=
+ Data->LHSType.getIntegerBitWidth()) {
+ R.setErrorType(ErrorType::InvalidShiftExponent);
+ Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2")
+ << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
+ } else if (LHSVal.isNegative()) {
+ R.setErrorType(ErrorType::InvalidShiftBase);
Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
- else
+ } else {
+ R.setErrorType(ErrorType::InvalidShiftBase);
Diag(Loc, DL_Error,
"left shift of %0 by %1 places cannot be represented in type %2")
- << LHSVal << RHSVal << Data->LHSType;
+ << LHSVal << RHSVal << Data->LHSType;
+ }
}
void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
@@ -221,7 +237,7 @@ static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::OutOfBoundsIndex);
Value IndexVal(Data->IndexType, Index);
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
@@ -242,7 +258,7 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
static void handleBuiltinUnreachableImpl(UnreachableData *Data,
ReportOptions Opts) {
- ScopedReport R(Opts, Data->Loc);
+ ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall);
Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
}
@@ -253,7 +269,7 @@ void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
}
static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
- ScopedReport R(Opts, Data->Loc);
+ ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn);
Diag(Data->Loc, DL_Error,
"execution reached the end of a value-returning function "
"without returning a value");
@@ -271,7 +287,7 @@ static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::NonPositiveVLAIndex);
Diag(Loc, DL_Error, "variable length array bound evaluates to "
"non-positive value %0")
@@ -328,7 +344,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
ToType = &Data->ToType;
}
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::FloatCastOverflow);
Diag(Loc, DL_Error,
"value %0 is outside the range of representable values of type %2")
@@ -352,7 +368,11 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ // 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);
Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
@@ -378,7 +398,7 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
if (ignoreReport(CallLoc, Opts))
return;
- ScopedReport R(Opts, CallLoc);
+ ScopedReport R(Opts, CallLoc, ErrorType::FunctionTypeMismatch);
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
const char *FName = FLoc.get()->info.function;
@@ -410,7 +430,7 @@ static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::InvalidNullReturn);
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
@@ -434,7 +454,7 @@ static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
if (ignoreReport(Loc, Opts))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::InvalidNullArgument);
Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
"never be null") << Data->ArgIndex;
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc
index 6984a963d..674e406c5 100644
--- a/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/lib/ubsan/ubsan_handlers_cxx.cc
@@ -45,7 +45,7 @@ static void HandleDynamicTypeCacheMiss(
if (Loc.isDisabled())
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::DynamicTypeMismatch);
Diag(Loc, DL_Error,
"%0 address %1 which does not point to an object of type %2")
@@ -85,7 +85,7 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ErrorType::CFIBadType);
DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void*)Vtable);
static const char *TypeCheckKinds[] = {