Skip to content

Commit

Permalink
[UBSan] Add the ability to print more precise error kind in summary l…
Browse files Browse the repository at this point in the history
…ine.

Reviewers: rsmith, pcc

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D12215

llvm-svn: 245897
  • Loading branch information
vonosmas committed Aug 24, 2015
1 parent 942b46a commit f3b9c89
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 48 deletions.
53 changes: 53 additions & 0 deletions compiler-rt/lib/ubsan/ubsan_checks.inc
Original file line number Diff line number Diff line change
@@ -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")
30 changes: 22 additions & 8 deletions compiler-rt/lib/ubsan/ubsan_diag.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down
11 changes: 10 additions & 1 deletion compiler-rt/lib/ubsan/ubsan_diag.h
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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();
};

Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/ubsan/ubsan_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
80 changes: 50 additions & 30 deletions compiler-rt/lib/ubsan/ubsan_handlers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand All @@ -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;
}

Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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")
Expand All @@ -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");
}

Expand All @@ -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");
Expand All @@ -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")
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand All @@ -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;
Expand Down Expand Up @@ -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");
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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[] = {
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t
// RUN: %run %t _
// RUN: env UBSAN_OPTIONS=print_summary=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
// RUN: env UBSAN_OPTIONS=print_summary=1:report_error_type=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
// RUN: %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1
// RUN: %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2
// RUN: %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3
Expand Down Expand Up @@ -88,7 +88,7 @@ int main(int argc, char **argv) {
// successfully round-trip, depending on the rounding mode.
// CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
static int test_int = MaxFloatRepresentableAsInt + 0x80;
// CHECK-0: SUMMARY: {{.*}}Sanitizer: undefined-behavior {{.*}}cast-overflow.cpp:[[@LINE-1]]
// CHECK-0: SUMMARY: {{.*}}Sanitizer: float-cast-overflow {{.*}}cast-overflow.cpp:[[@LINE-1]]
return 0;
}
case '1': {
Expand Down
Loading

0 comments on commit f3b9c89

Please sign in to comment.