From 2c36c71f5b5daae99f173aea32ef34497a7a4a48 Mon Sep 17 00:00:00 2001 From: Will Dietz Date: Sun, 2 Dec 2012 19:47:29 +0000 Subject: [PATCH] [ubsan] Refactor handlers to have separate entry points for aborting. If user specifies aborting after a recoverable failed check is appropriate, frontend should emit call to the _abort variant. Test this behavior with newly added -fsanitize-recover flag. llvm-svn: 169113 --- .../lib/ubsan/lit_tests/Integer/no-recover.cpp | 21 ++++++++++ compiler-rt/lib/ubsan/ubsan_handlers.cc | 47 +++++++++++++++++++++- compiler-rt/lib/ubsan/ubsan_handlers.h | 42 +++++++++---------- compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc | 17 ++++++-- compiler-rt/lib/ubsan/ubsan_handlers_cxx.h | 2 + 5 files changed, 102 insertions(+), 27 deletions(-) create mode 100644 compiler-rt/lib/ubsan/lit_tests/Integer/no-recover.cpp diff --git a/compiler-rt/lib/ubsan/lit_tests/Integer/no-recover.cpp b/compiler-rt/lib/ubsan/lit_tests/Integer/no-recover.cpp new file mode 100644 index 0000000..08324bd --- /dev/null +++ b/compiler-rt/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 + +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/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc index 6f5a821..47f06e8 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cc +++ b/compiler-rt/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 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/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h index f7bd56c..5709fcf 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc index 1f61d2b..593fe13 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc +++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h index 8192e65..0fbcafb 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.h +++ b/compiler-rt/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); } -- 2.7.4