forked from OSchip/llvm-project
[ubsan] Add deduplication functionality, always enabled.
llvm-svn: 171948
This commit is contained in:
parent
450f1a1f45
commit
765c266892
|
@ -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 <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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<typename T> 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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue