summaryrefslogtreecommitdiff
path: root/lib/ubsan
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ubsan')
-rw-r--r--lib/ubsan/lit_tests/Integer/no-recover.cpp21
-rw-r--r--lib/ubsan/ubsan_handlers.cc47
-rw-r--r--lib/ubsan/ubsan_handlers.h42
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc17
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.h2
5 files changed, 102 insertions, 27 deletions
diff --git a/lib/ubsan/lit_tests/Integer/no-recover.cpp b/lib/ubsan/lit_tests/Integer/no-recover.cpp
new file mode 100644
index 000000000..08324bd60
--- /dev/null
+++ b/lib/ubsan/lit_tests/Integer/no-recover.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang -fsanitize=unsigned-integer-overflow -Xclang -fsanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER
+// RUN: %clang -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ABORT
+
+#include <stdint.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(uint8_t(0xff) + uint8_t(0xff));
+ (void)(uint16_t(0xf0fff) + uint16_t(0x0fff));
+ // RECOVER-NOT: runtime error
+ // ABORT-NOT: runtime error
+
+ uint32_t k = 0x87654321;
+ k += 0xedcba987;
+ // RECOVER: no-recover.cpp:14:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'uint32_t' (aka 'unsigned int')
+ // ABORT: no-recover.cpp:14:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'uint32_t' (aka 'unsigned int')
+
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // RECOVER: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned long'
+ // ABORT-NOT: runtime error
+}
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 6f5a82198..47f06e8f4 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -40,6 +40,10 @@ void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
Diag(Data->Loc, "%0 address %1 with insufficient space "
"for an object of type %2")
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+}
+void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
+ ValueHandle Pointer) {
+ __ubsan_handle_type_mismatch(Data, Pointer);
Die();
}
@@ -52,29 +56,50 @@ template<typename T> static void HandleIntegerOverflow(OverflowData *Data,
"%1 %2 %3 cannot be represented in type %4")
<< (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
- Die();
}
void __ubsan::__ubsan_handle_add_overflow(OverflowData *Data,
ValueHandle LHS, ValueHandle RHS) {
HandleIntegerOverflow(Data, LHS, "+", Value(Data->Type, RHS));
}
+void __ubsan::__ubsan_handle_add_overflow_abort(OverflowData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ __ubsan_handle_add_overflow(Data, LHS, RHS);
+ Die();
+}
void __ubsan::__ubsan_handle_sub_overflow(OverflowData *Data,
ValueHandle LHS, ValueHandle RHS) {
HandleIntegerOverflow(Data, LHS, "-", Value(Data->Type, RHS));
}
+void __ubsan::__ubsan_handle_sub_overflow_abort(OverflowData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ __ubsan_handle_sub_overflow(Data, LHS, RHS);
+ Die();
+}
void __ubsan::__ubsan_handle_mul_overflow(OverflowData *Data,
ValueHandle LHS, ValueHandle RHS) {
HandleIntegerOverflow(Data, LHS, "*", Value(Data->Type, RHS));
}
+void __ubsan::__ubsan_handle_mul_overflow_abort(OverflowData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ __ubsan_handle_mul_overflow(Data, LHS, RHS);
+ Die();
+}
void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
ValueHandle OldVal) {
Diag(Data->Loc, "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;
+}
+void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
+ ValueHandle OldVal) {
+ __ubsan_handle_negate_overflow(Data, OldVal);
Die();
}
@@ -87,6 +112,11 @@ void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
<< LHSVal << Data->Type;
else
Diag(Data->Loc, "division by zero");
+}
+void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ __ubsan_handle_divrem_overflow(Data, LHS, RHS);
Die();
}
@@ -105,6 +135,12 @@ void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
else
Diag(Data->Loc, "left shift of %0 by %1 places cannot be represented "
"in type %2") << LHSVal << RHSVal << Data->LHSType;
+}
+void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
+ ShiftOutOfBoundsData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ __ubsan_handle_shift_out_of_bounds(Data, LHS, RHS);
Die();
}
@@ -124,6 +160,10 @@ void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
Diag(Data->Loc, "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,
+ ValueHandle Bound) {
+ __ubsan_handle_vla_bound_not_positive(Data, Bound);
Die();
}
@@ -132,5 +172,10 @@ void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
Diag(SourceLocation(), "value %0 is outside the range of representable "
"values of type %2")
<< Value(Data->FromType, From) << Data->FromType << Data->ToType;
+}
+void __ubsan::__ubsan_handle_float_cast_overflow_abort(
+ FloatCastOverflowData *Data,
+ ValueHandle From) {
+ __ubsan_handle_float_cast_overflow(Data, From);
Die();
}
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index f7bd56c06..5709fcf67 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -24,11 +24,14 @@ struct TypeMismatchData {
unsigned char TypeCheckKind;
};
+#define RECOVERABLE(checkname, ...) \
+ extern "C" void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
+ extern "C" void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
+
/// \brief Handle a runtime type check failure, caused by either a misaligned
/// pointer, a null pointer, or a pointer to insufficient storage for the
/// type.
-extern "C" void __ubsan_handle_type_mismatch(TypeMismatchData *Data,
- ValueHandle Pointer);
+RECOVERABLE(type_mismatch, TypeMismatchData *Data, ValueHandle Pointer)
struct OverflowData {
SourceLocation Loc;
@@ -36,24 +39,20 @@ struct OverflowData {
};
/// \brief Handle an integer addition overflow.
-extern "C" void __ubsan_handle_add_overflow(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS);
+RECOVERABLE(add_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
/// \brief Handle an integer subtraction overflow.
-extern "C" void __ubsan_handle_sub_overflow(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS);
+RECOVERABLE(sub_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
/// \brief Handle an integer multiplication overflow.
-extern "C" void __ubsan_handle_mul_overflow(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS);
+RECOVERABLE(mul_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
+
/// \brief Handle a signed integer overflow for a unary negate operator.
-extern "C" void __ubsan_handle_negate_overflow(OverflowData *Data,
- ValueHandle OldVal);
+RECOVERABLE(negate_overflow, OverflowData *Data, ValueHandle OldVal)
+
/// \brief Handle an INT_MIN/-1 overflow or division by zero.
-extern "C" void __ubsan_handle_divrem_overflow(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS);
+RECOVERABLE(divrem_overflow, OverflowData *Data,
+ ValueHandle LHS, ValueHandle RHS)
struct ShiftOutOfBoundsData {
SourceLocation Loc;
@@ -63,9 +62,8 @@ struct ShiftOutOfBoundsData {
/// \brief Handle a shift where the RHS is out of bounds or a left shift where
/// the LHS is negative or overflows.
-extern "C" void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
- ValueHandle LHS,
- ValueHandle RHS);
+RECOVERABLE(shift_out_of_bounds, ShiftOutOfBoundsData *Data,
+ ValueHandle LHS, ValueHandle RHS)
struct UnreachableData {
SourceLocation Loc;
@@ -82,8 +80,7 @@ struct VLABoundData {
};
/// \brief Handle a VLA with a non-positive bound.
-extern "C" void __ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
- ValueHandle Bound);
+RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
struct FloatCastOverflowData {
// FIXME: SourceLocation Loc;
@@ -92,8 +89,7 @@ struct FloatCastOverflowData {
};
/// \brief Handle overflow in a conversion to or from a floating-point type.
-extern "C" void __ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
- ValueHandle From);
+RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
}
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc
index 1f61d2b07..593fe1312 100644
--- a/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/lib/ubsan/ubsan_handlers_cxx.cc
@@ -26,8 +26,9 @@ namespace __ubsan {
extern const char *TypeCheckKinds[];
}
-void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
- DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+static void HandleDynamicTypeCacheMiss(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
+ bool abort) {
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
// Just a cache miss. The type matches after all.
return;
@@ -45,5 +46,15 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
// 00 00 00 00 e0 f7 c5 09 00 00 00 00 20 00 00 00
// ^~~~~~~~~~~
// vptr for 'llvm::BinaryOperator'
- Die();
+ if (abort)
+ Die();
+}
+
+void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false);
+}
+void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true);
}
diff --git a/lib/ubsan/ubsan_handlers_cxx.h b/lib/ubsan/ubsan_handlers_cxx.h
index 8192e6527..0fbcafb14 100644
--- a/lib/ubsan/ubsan_handlers_cxx.h
+++ b/lib/ubsan/ubsan_handlers_cxx.h
@@ -30,6 +30,8 @@ struct DynamicTypeCacheMissData {
/// cache; this does not necessarily imply the existence of a bug.
extern "C" void __ubsan_handle_dynamic_type_cache_miss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
+extern "C" void __ubsan_handle_dynamic_type_cache_miss_abort(
+ DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
}