diff --git a/compiler-rt/lib/ubsan/lit_tests/Misc/deduplication.cpp b/compiler-rt/lib/ubsan/lit_tests/Misc/deduplication.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9c909f9af4f84526c7de45fc08d804678851922 --- /dev/null +++ b/compiler-rt/lib/ubsan/lit_tests/Misc/deduplication.cpp @@ -0,0 +1,25 @@ +// RUN: %clang -fsanitize=undefined %s -o %t && %t 2>&1 | FileCheck %s +// Verify deduplication works by ensuring only one diag is emitted. +#include +#include + +void overflow() { + int i = INT_MIN; + --i; +} + +int main() { + // CHECK: Start + fprintf(stderr, "Start\n"); + + // CHECK: runtime error + // CHECK-NOT: runtime error + // CHECK-NOT: runtime error + overflow(); + overflow(); + overflow(); + + // CHECK: End + fprintf(stderr, "End\n"); + return 0; +} diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc index 0303e4361406c1190a0410b18766ac5137be3b06..1b02aa0fadf3e20aa749c2e3a45cee193042063e 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cc +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cc @@ -28,7 +28,11 @@ namespace __ubsan { static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, Location FallbackLoc) { - Location Loc = Data->Loc; + Location Loc = Data->Loc.acquire(); + + // Use the SourceLocation from Data to track deduplication, even if 'invalid' + if (Loc.getSourceLocation().isDisabled()) + return; if (Data->Loc.isInvalid()) Loc = FallbackLoc; @@ -62,8 +66,12 @@ template static void HandleIntegerOverflow(OverflowData *Data, ValueHandle LHS, const char *Operator, T RHS) { - Diag(Data->Loc, DL_Error, "%0 integer overflow: " - "%1 %2 %3 cannot be represented in type %4") + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + + Diag(Loc, DL_Error, "%0 integer overflow: " + "%1 %2 %3 cannot be represented in type %4") << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned") << Value(Data->Type, LHS) << Operator << RHS << Data->Type; } @@ -103,13 +111,17 @@ void __ubsan::__ubsan_handle_mul_overflow_abort(OverflowData *Data, void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, ValueHandle OldVal) { + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + if (Data->Type.isSignedIntegerTy()) - Diag(Data->Loc, DL_Error, + 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; else - Diag(Data->Loc, DL_Error, + Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") << Value(Data->Type, OldVal) << Data->Type; } @@ -121,14 +133,18 @@ void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, ValueHandle LHS, ValueHandle RHS) { + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + Value LHSVal(Data->Type, LHS); Value RHSVal(Data->Type, RHS); if (RHSVal.isMinusOne()) - Diag(Data->Loc, DL_Error, + Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1") << LHSVal << Data->Type; else - Diag(Data->Loc, DL_Error, "division by zero"); + Diag(Loc, DL_Error, "division by zero"); } void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, ValueHandle LHS, @@ -140,18 +156,22 @@ void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, ValueHandle LHS, ValueHandle RHS) { + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + Value LHSVal(Data->LHSType, LHS); Value RHSVal(Data->RHSType, RHS); if (RHSVal.isNegative()) - Diag(Data->Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; + Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) - Diag(Data->Loc, DL_Error, + 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()) - Diag(Data->Loc, DL_Error, "left shift of negative value %0") << LHSVal; + Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; else - Diag(Data->Loc, DL_Error, + Diag(Loc, DL_Error, "left shift of %0 by %1 places cannot be represented in type %2") << LHSVal << RHSVal << Data->LHSType; } @@ -177,8 +197,12 @@ void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, ValueHandle Bound) { - Diag(Data->Loc, DL_Error, "variable length array bound evaluates to " - "non-positive value %0") + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + + Diag(Loc, DL_Error, "variable length array bound evaluates to " + "non-positive value %0") << Value(Data->Type, Bound); } void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, @@ -190,6 +214,7 @@ void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data, ValueHandle From) { + // TODO: Add deduplication once a SourceLocation is generated for this check. Diag(getCallerLocation(), DL_Error, "value %0 is outside the range of representable values of type %2") << Value(Data->FromType, From) << Data->FromType << Data->ToType; @@ -205,6 +230,7 @@ void __ubsan::__ubsan_handle_float_cast_overflow_abort( void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, ValueHandle Val) { + // TODO: Add deduplication once a SourceLocation is generated for this check. Diag(getCallerLocation(), DL_Error, "load of value %0, which is not a valid value for type %1") << Value(Data->Type, Val) << Data->Type; diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc index b199dc7d5a78c0c5fac53b2173bf6e193fbc826b..dcc1f60078d2ade1531a64a3efe71616ee79c432 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc +++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc @@ -33,7 +33,11 @@ static void HandleDynamicTypeCacheMiss( // Just a cache miss. The type matches after all. return; - Diag(Data->Loc, DL_Error, + SourceLocation Loc = Data->Loc.acquire(); + if (Loc.isDisabled()) + return; + + Diag(Loc, DL_Error, "%0 address %1 which does not point to an object of type %2") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; diff --git a/compiler-rt/lib/ubsan/ubsan_value.h b/compiler-rt/lib/ubsan/ubsan_value.h index 21313fc36a416cf248995e3a74a7d056199a5be9..55a1ba92188198241d2790879b0fe212f80398c3 100644 --- a/compiler-rt/lib/ubsan/ubsan_value.h +++ b/compiler-rt/lib/ubsan/ubsan_value.h @@ -46,7 +46,6 @@ typedef u64 UIntMax; /// \brief Largest floating-point type we support. typedef long double FloatMax; - /// \brief A description of a source location. This corresponds to Clang's /// \c PresumedLoc type. class SourceLocation { @@ -62,6 +61,25 @@ public: /// \brief Determine whether the source location is known. bool isInvalid() const { return !Filename; } + /// \brief Atomically acquire a copy, disabling original in-place. + /// Exactly one call to acquire() returns a copy that isn't disabled. + SourceLocation acquire() { +#ifdef __ATOMIC_RELAXED + // Use weaker ordering if available (relaxed/monotonic) + u32 OldColumn = __atomic_exchange_n(&Column, ~u32(0), __ATOMIC_RELAXED); +#else + // Otherwise, do a TAS which has acquire semantics, stronger than needed. + u32 OldColumn = __sync_lock_test_and_set(&Column, ~u32(0)); +#endif + return SourceLocation(Filename, Line, OldColumn); + } + + /// \brief Determine if this Location has been disabled. + /// Disabled SourceLocations are invalid to use. + bool isDisabled() { + return Column == ~u32(0); + } + /// \brief Get the presumed filename for the source location. const char *getFilename() const { return Filename; } /// \brief Get the presumed line number.