diff options
author | Alexey Samsonov <vonosmas@gmail.com> | 2015-08-24 23:18:49 +0000 |
---|---|---|
committer | Alexey Samsonov <vonosmas@gmail.com> | 2015-08-24 23:18:49 +0000 |
commit | aef60033031849c68092f304d04bf609b3c269ff (patch) | |
tree | aff383ccd60e135ca8ef2b5879fc6cd315006395 /lib/ubsan | |
parent | b1900f9b3f936a8f84cd42d1aabd899613f32137 (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.inc | 53 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.cc | 30 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.h | 11 | ||||
-rw-r--r-- | lib/ubsan/ubsan_flags.inc | 3 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers.cc | 80 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.cc | 4 |
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[] = { |