diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
commit | ca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch) | |
tree | 9b19e801150082c33e9152275829a6ce90614b55 /lib/ubsan | |
parent | 8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff) | |
download | src-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.tar.gz src-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.zip |
Import compiler-rt trunk r224034.vendor/compiler-rt/compiler-rt-r224034
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=276789
svn path=/vendor/compiler-rt/compiler-rt-r224034/; revision=276790; tag=vendor/compiler-rt/compiler-rt-r224034
Diffstat (limited to 'lib/ubsan')
45 files changed, 652 insertions, 1023 deletions
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 675c47f6a65e..09c7a851e075 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -2,6 +2,8 @@ set(UBSAN_SOURCES ubsan_diag.cc + ubsan_init.cc + ubsan_flags.cc ubsan_handlers.cc ubsan_value.cc ) @@ -14,11 +16,10 @@ set(UBSAN_CXX_SOURCES include_directories(..) set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_no_rtti_flag(UBSAN_CFLAGS) +set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) -filter_available_targets(UBSAN_SUPPORTED_ARCH - x86_64 i386) - -set(UBSAN_RUNTIME_LIBRARIES) +add_custom_target(ubsan) if(APPLE) # Build universal binary on APPLE. @@ -26,31 +27,31 @@ if(APPLE) ARCH ${UBSAN_SUPPORTED_ARCH} SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES} $<TARGET_OBJECTS:RTSanitizerCommon.osx> - CFLAGS ${UBSAN_CFLAGS}) - list(APPEND UBSAN_RUNTIME_LIBRARIES clang_rt.ubsan_osx) + CFLAGS ${UBSAN_CXXFLAGS}) + add_dependencies(ubsan clang_rt.ubsan_osx) else() # Build separate libraries for each target. foreach(arch ${UBSAN_SUPPORTED_ARCH}) # Main UBSan runtime. - add_compiler_rt_static_runtime(clang_rt.ubsan-${arch} ${arch} + add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS}) # C++-specific parts of UBSan runtime. Requires a C++ ABI library. - add_compiler_rt_static_runtime(clang_rt.ubsan_cxx-${arch} ${arch} + add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC SOURCES ${UBSAN_CXX_SOURCES} - CFLAGS ${UBSAN_CFLAGS}) - list(APPEND UBSAN_RUNTIME_LIBRARIES + CFLAGS ${UBSAN_CXXFLAGS}) + add_dependencies(ubsan clang_rt.san-${arch} clang_rt.ubsan-${arch} clang_rt.ubsan_cxx-${arch}) - if (UNIX AND NOT ${arch} STREQUAL "i386") + if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686") add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra) add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra) - list(APPEND UBSAN_RUNTIME_LIBRARIES + add_dependencies(ubsan clang_rt.ubsan-${arch}-symbols clang_rt.ubsan_cxx-${arch}-symbols) endif() endforeach() endif() -add_subdirectory(lit_tests) +add_dependencies(compiler-rt ubsan) diff --git a/lib/ubsan/lit_tests/AsanConfig/lit.cfg b/lib/ubsan/lit_tests/AsanConfig/lit.cfg deleted file mode 100644 index 407e5ec32e60..000000000000 --- a/lib/ubsan/lit_tests/AsanConfig/lit.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -ubsan_lit_tests_dir = get_required_attr(config, "ubsan_lit_tests_dir") -ubsan_lit_cfg = os.path.join(ubsan_lit_tests_dir, "lit.common.cfg") -lit_config.load_config(config, ubsan_lit_cfg) - -config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer' - -# Define %clang and %clangxx substitutions to use in test RUN lines. -config.substitutions.append( ("%clang ", (" " + config.clang + - " -fsanitize=address ")) ) -config.substitutions.append( ("%clangxx ", (" " + config.clang + - " -fsanitize=address" + - " --driver-mode=g++ ")) ) diff --git a/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in b/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in deleted file mode 100644 index f75741838f83..000000000000 --- a/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in +++ /dev/null @@ -1,9 +0,0 @@ -# Load common config for all compiler-rt lit tests. -lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") - -# Tool-specific config options. -config.ubsan_lit_tests_dir = "@UBSAN_LIT_TESTS_DIR@" - -# Load tool-specific config that would do the real work. -print config.ubsan_lit_tests_dir -lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/AsanConfig/lit.cfg") diff --git a/lib/ubsan/lit_tests/CMakeLists.txt b/lib/ubsan/lit_tests/CMakeLists.txt deleted file mode 100644 index 36d8dc1f9205..000000000000 --- a/lib/ubsan/lit_tests/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/UbsanConfig/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig/lit.site.cfg) - -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg) - -if(COMPILER_RT_CAN_EXECUTE_TESTS) - # Run UBSan output tests only if we're sure that clang would produce - # working binaries. - set(UBSAN_TEST_DEPS - ${SANITIZER_COMMON_LIT_TEST_DEPS} - ${UBSAN_RUNTIME_LIBRARIES} - asan_runtime_libraries) - add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests" - ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig - ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig - DEPENDS ${UBSAN_TEST_DEPS}) - set_target_properties(check-ubsan PROPERTIES FOLDER "UBSan unittests") -endif() diff --git a/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp deleted file mode 100644 index 35f9336c904a..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t -// RUN: %t _ -// RUN: %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0 -// RUN: %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1 -// RUN: %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2 -// RUN: %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3 -// RUN: %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4 -// RUN: %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5 -// RUN: %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6 -// FIXME: %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7 -// RUN: %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8 - -// This test assumes float and double are IEEE-754 single- and double-precision. - -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -float Inf; -float NaN; - -int main(int argc, char **argv) { - float MaxFloatRepresentableAsInt = 0x7fffff80; - (int)MaxFloatRepresentableAsInt; // ok - (int)-MaxFloatRepresentableAsInt; // ok - - float MinFloatRepresentableAsInt = -0x7fffffff - 1; - (int)MinFloatRepresentableAsInt; // ok - - float MaxFloatRepresentableAsUInt = 0xffffff00u; - (unsigned int)MaxFloatRepresentableAsUInt; // ok - -#ifdef __SIZEOF_INT128__ - unsigned __int128 FloatMaxAsUInt128 = -((unsigned __int128)1 << 104); - (void)(float)FloatMaxAsUInt128; // ok -#endif - - float NearlyMinusOne = -0.99999; - unsigned Zero = NearlyMinusOne; // ok - - // Build a '+Inf'. - char InfVal[] = { 0x00, 0x00, 0x80, 0x7f }; - float Inf; - memcpy(&Inf, InfVal, 4); - - // Build a 'NaN'. - char NaNVal[] = { 0x01, 0x00, 0x80, 0x7f }; - float NaN; - memcpy(&NaN, NaNVal, 4); - - double DblInf = (double)Inf; // ok - - switch (argv[1][0]) { - // FIXME: Produce a source location for these checks and test for it here. - - // Floating point -> integer overflow. - case '0': - // Note that values between 0x7ffffe00 and 0x80000000 may or may not - // successfully round-trip, depending on the rounding mode. - // CHECK-0: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int' - return MaxFloatRepresentableAsInt + 0x80; - case '1': - // CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int' - return MinFloatRepresentableAsInt - 0x100; - case '2': - // CHECK-2: runtime error: value -1 is outside the range of representable values of type 'unsigned int' - return (unsigned)-1.0; - case '3': - // CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int' - return (unsigned)(MaxFloatRepresentableAsUInt + 0x100); - - case '4': - // CHECK-4: runtime error: value {{.*}} is outside the range of representable values of type 'int' - return Inf; - case '5': - // CHECK-5: runtime error: value {{.*}} is outside the range of representable values of type 'int' - return NaN; - - // Integer -> floating point overflow. - case '6': - // CHECK-6: {{runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'|__int128 not supported}} -#ifdef __SIZEOF_INT128__ - return (float)(FloatMaxAsUInt128 + 1); -#else - puts("__int128 not supported"); - return 0; -#endif - // FIXME: The backend cannot lower __fp16 operations on x86 yet. - //case '7': - // (__fp16)65504; // ok - // // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16' - // return (__fp16)65505; - - // Floating point -> floating point overflow. - case '8': - // CHECK-8: runtime error: value 1e+39 is outside the range of representable values of type 'float' - return (float)1e39; - } -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp deleted file mode 100644 index 412eb7621033..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: %clangxx -DADD_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32 -// RUN: %clangxx -DADD_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64 -// RUN: %clangxx -DADD_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128 - -#include <stdint.h> -#include <stdio.h> - -int main() { - // These promote to 'int'. - (void)(int8_t(0x7f) + int8_t(0x7f)); - (void)(int16_t(0x3fff) + int16_t(0x4000)); - -#ifdef ADD_I32 - int32_t k = 0x12345678; - k += 0x789abcde; - // CHECK-ADD_I32: add-overflow.cpp:[[@LINE-1]]:5: runtime error: signed integer overflow: 305419896 + 2023406814 cannot be represented in type 'int' -#endif - -#ifdef ADD_I64 - (void)(int64_t(8000000000000000000ll) + int64_t(2000000000000000000ll)); - // CHECK-ADD_I64: 8000000000000000000 + 2000000000000000000 cannot be represented in type '{{long( long)?}}' -#endif - -#ifdef ADD_I128 -# ifdef __SIZEOF_INT128__ - (void)((__int128_t(1) << 126) + (__int128_t(1) << 126)); -# else - puts("__int128 not supported"); -# endif - // CHECK-ADD_I128: {{0x40000000000000000000000000000000 \+ 0x40000000000000000000000000000000 cannot be represented in type '__int128'|__int128 not supported}} -#endif -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp deleted file mode 100644 index 83aa854485b4..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s - -#include <stdint.h> - -int main() { - unsigned(0x80000000) / -1; - - // CHECK: div-overflow.cpp:9:23: runtime error: division of -2147483648 by -1 cannot be represented in type 'int' - int32_t(0x80000000) / -1; -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp deleted file mode 100644 index 6b8aadfe15e6..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=1U %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -fsanitize=float-divide-by-zero -DDIVIDEND=1.5 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND='intmax(123)' %s -o %t && %t 2>&1 | FileCheck %s - -#ifdef __SIZEOF_INT128__ -typedef __int128 intmax; -#else -typedef long long intmax; -#endif - -int main() { - // CHECK: div-zero.cpp:[[@LINE+1]]:12: runtime error: division by zero - DIVIDEND / 0; -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp deleted file mode 100644 index 904250a76c79..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx -DOP=n++ -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -DOP=++n -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -DOP=m-- -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx -DOP=--m -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s - -#include <stdint.h> - -int main() { - int n = 0x7ffffffd; - n++; - n++; - int m = -n - 1; - // CHECK: incdec-overflow.cpp:15:3: runtime error: signed integer overflow: [[MINUS:-?]]214748364 - // CHECK: + [[MINUS]]1 cannot be represented in type 'int' - OP; -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp deleted file mode 100644 index 1cfe23f57213..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s - -#include <stdint.h> - -int main() { - // These promote to 'int'. - (void)(int8_t(-2) * int8_t(0x7f)); - (void)(int16_t(0x7fff) * int16_t(0x7fff)); - (void)(uint16_t(0xffff) * int16_t(0x7fff)); - (void)(uint16_t(0xffff) * uint16_t(0x8000)); - - // CHECK: mul-overflow.cpp:13:27: runtime error: signed integer overflow: 65535 * 32769 cannot be represented in type 'int' - (void)(uint16_t(0xffff) * uint16_t(0x8001)); -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp deleted file mode 100644 index 6bee3eea2980..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKS -// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKU - -int main() { - // CHECKS-NOT: runtime error - // CHECKU: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int' - // CHECKU-NOT: cast to an unsigned - -unsigned(-0x7fffffff - 1); // ok - // CHECKS: negate-overflow.cpp:[[@LINE+2]]:10: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself - // CHECKU-NOT: runtime error - return -(-0x7fffffff - 1); -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp b/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp deleted file mode 100644 index 64787b7cfbf5..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER -// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER -// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %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:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int' - // ABORT: no-recover.cpp:[[@LINE-2]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int' - - (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull)); - // RECOVER: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}' - // ABORT-NOT: runtime error -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp b/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp deleted file mode 100644 index f35fa1f959ae..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW -// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW -// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH - -#include <stdint.h> - -int main() { - int a = 1; - unsigned b = 1; - - a <<= 31; // ok in C++11, not ok in C99/C11 - b <<= 31; // ok - b <<= 1; // still ok, unsigned - -#ifdef LSH_OVERFLOW - // CHECK-LSH_OVERFLOW: shift.cpp:24:5: runtime error: left shift of negative value -2147483648 - a OP 1; -#endif - -#ifdef TOO_LOW - // CHECK-TOO_LOW: shift.cpp:29:5: runtime error: shift exponent -3 is negative - a OP (-3); -#endif - -#ifdef TOO_HIGH - a = 0; - // CHECK-TOO_HIGH: shift.cpp:35:5: runtime error: shift exponent 32 is too large for 32-bit type 'int' - a OP 32; -#endif -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp deleted file mode 100644 index bf33d293799b..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clangxx -DSUB_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32 -// RUN: %clangxx -DSUB_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64 -// RUN: %clangxx -DSUB_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128 - -#include <stdint.h> -#include <stdio.h> - -int main() { - // These promote to 'int'. - (void)(int8_t(-2) - int8_t(0x7f)); - (void)(int16_t(-2) - int16_t(0x7fff)); - -#ifdef SUB_I32 - (void)(int32_t(-2) - int32_t(0x7fffffff)); - // CHECK-SUB_I32: sub-overflow.cpp:[[@LINE-1]]:22: runtime error: signed integer overflow: -2 - 2147483647 cannot be represented in type 'int' -#endif - -#ifdef SUB_I64 - (void)(int64_t(-8000000000000000000ll) - int64_t(2000000000000000000ll)); - // CHECK-SUB_I64: -8000000000000000000 - 2000000000000000000 cannot be represented in type '{{long( long)?}}' -#endif - -#ifdef SUB_I128 -# ifdef __SIZEOF_INT128__ - (void)(-(__int128_t(1) << 126) - (__int128_t(1) << 126) - 1); -# else - puts("__int128 not supported"); -# endif - // CHECK-SUB_I128: {{0x80000000000000000000000000000000 - 1 cannot be represented in type '__int128'|__int128 not supported}} -#endif -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp deleted file mode 100644 index 2ef31c0640d1..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: %clangxx -DADD_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32 -// RUN: %clangxx -DADD_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64 -// RUN: %clangxx -DADD_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128 - -#include <stdint.h> -#include <stdio.h> - -int main() { - // These promote to 'int'. - (void)(uint8_t(0xff) + uint8_t(0xff)); - (void)(uint16_t(0xf0fff) + uint16_t(0x0fff)); - -#ifdef ADD_I32 - uint32_t k = 0x87654321; - k += 0xedcba987; - // CHECK-ADD_I32: uadd-overflow.cpp:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int' -#endif - -#ifdef ADD_I64 - (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull)); - // CHECK-ADD_I64: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}' -#endif - -#ifdef ADD_I128 -# ifdef __SIZEOF_INT128__ - (void)((__uint128_t(1) << 127) + (__uint128_t(1) << 127)); -# else - puts("__int128 not supported"); -# endif - // CHECK-ADD_I128: {{0x80000000000000000000000000000000 \+ 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}} -#endif -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp deleted file mode 100644 index a14bd6a776f5..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx -DOP=n++ -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s -// RUN: %clangxx -DOP=++n -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s -// RUN: %clangxx -DOP=m-- -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s -// RUN: %clangxx -DOP=--m -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s - -#include <stdint.h> - -int main() { - unsigned n = 0xfffffffd; - n++; - n++; - unsigned m = 0; - // CHECK-INC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 4294967295 + 1 cannot be represented in type 'unsigned int' - // CHECK-DEC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int' - OP; -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp deleted file mode 100644 index c84bb39ef2f7..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s - -#include <stdint.h> - -int main() { - // These promote to 'int'. - (void)(int8_t(-2) * int8_t(0x7f)); - (void)(int16_t(0x7fff) * int16_t(0x7fff)); - (void)(uint16_t(0xffff) * int16_t(0x7fff)); - (void)(uint16_t(0xffff) * uint16_t(0x8000)); - - // Not an unsigned overflow - (void)(uint16_t(0xffff) * uint16_t(0x8001)); - - (void)(uint32_t(0xffffffff) * uint32_t(0x2)); - // CHECK: umul-overflow.cpp:15:31: runtime error: unsigned integer overflow: 4294967295 * 2 cannot be represented in type 'unsigned int' - - return 0; -} diff --git a/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp deleted file mode 100644 index 78f745578583..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clangxx -DSUB_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32 -// RUN: %clangxx -DSUB_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64 -// RUN: %clangxx -DSUB_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128 - -#include <stdint.h> -#include <stdio.h> - -int main() { - // These promote to 'int'. - (void)(uint8_t(0) - uint8_t(0x7f)); - (void)(uint16_t(0) - uint16_t(0x7fff)); - -#ifdef SUB_I32 - (void)(uint32_t(1) - uint32_t(2)); - // CHECK-SUB_I32: usub-overflow.cpp:[[@LINE-1]]:22: runtime error: unsigned integer overflow: 1 - 2 cannot be represented in type 'unsigned int' -#endif - -#ifdef SUB_I64 - (void)(uint64_t(8000000000000000000ll) - uint64_t(9000000000000000000ll)); - // CHECK-SUB_I64: 8000000000000000000 - 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}' -#endif - -#ifdef SUB_I128 -# ifdef __SIZEOF_INT128__ - (void)((__uint128_t(1) << 126) - (__uint128_t(1) << 127)); -# else - puts("__int128 not supported\n"); -# endif - // CHECK-SUB_I128: {{0x40000000000000000000000000000000 - 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}} -#endif -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp deleted file mode 100644 index e916e7fb3c1d..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clangxx -fsanitize=bool %s -O3 -o %T/bool.exe && %T/bool.exe 2>&1 | FileCheck %s - -unsigned char NotABool = 123; - -int main(int argc, char **argv) { - bool *p = (bool*)&NotABool; - - // CHECK: bool.cpp:9:10: runtime error: load of value 123, which is not a valid value for type 'bool' - return *p; -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp deleted file mode 100644 index dc4c4a513c1c..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx -fsanitize=bounds %s -O3 -o %T/bounds.exe -// RUN: %T/bounds.exe 0 0 0 -// RUN: %T/bounds.exe 1 2 3 -// RUN: %T/bounds.exe 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2 -// RUN: %T/bounds.exe 0 3 0 2>&1 | FileCheck %s --check-prefix=CHECK-B-3 -// RUN: %T/bounds.exe 0 0 4 2>&1 | FileCheck %s --check-prefix=CHECK-C-4 - -int main(int argc, char **argv) { - int arr[2][3][4] = {}; - - return arr[argv[1][0] - '0'][argv[2][0] - '0'][argv[3][0] - '0']; - // CHECK-A-2: bounds.cpp:11:10: runtime error: index 2 out of bounds for type 'int [2][3][4]' - // CHECK-B-3: bounds.cpp:11:10: runtime error: index 3 out of bounds for type 'int [3][4]' - // CHECK-C-4: bounds.cpp:11:10: runtime error: index 4 out of bounds for type 'int [4]' -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp b/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp deleted file mode 100644 index d325bf6dd899..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %clangxx -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; -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp b/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp deleted file mode 100644 index c5642507ad42..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clangxx -fsanitize=enum %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN -// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %t -// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL - -enum E { a = 1 } e; -#undef E - -int main(int argc, char **argv) { - // memset(&e, 0xff, sizeof(e)); - for (unsigned char *p = (unsigned char*)&e; p != (unsigned char*)(&e + 1); ++p) - *p = 0xff; - - // CHECK-PLAIN: error: load of value 4294967295, which is not a valid value for type 'enum E' - // FIXME: Support marshalling and display of enum class values. - // CHECK-BOOL: error: load of value <unknown>, which is not a valid value for type 'enum E' - return (int)e != -1; -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp b/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp deleted file mode 100644 index 7da238e25dca..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// RUN: %clangxx -fsanitize=return %s -O3 -o %t && %t 2>&1 | FileCheck %s - -// CHECK: missing_return.cpp:4:5: runtime error: execution reached the end of a value-returning function without returning a value -int f() { -} - -int main(int, char **argv) { - return f(); -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp b/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp deleted file mode 100644 index 75fc3e5bd9a6..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && %t 2>&1 | FileCheck %s - -int main(int, char **argv) { - // CHECK: unreachable.cpp:5:3: runtime error: execution reached a __builtin_unreachable() call - __builtin_unreachable(); -} diff --git a/lib/ubsan/lit_tests/TestCases/Misc/vla.c b/lib/ubsan/lit_tests/TestCases/Misc/vla.c deleted file mode 100644 index 2fa88addc0d3..000000000000 --- a/lib/ubsan/lit_tests/TestCases/Misc/vla.c +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang -fsanitize=vla-bound %s -O3 -o %t -// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-MINUS-ONE -// RUN: %t a 2>&1 | FileCheck %s --check-prefix=CHECK-ZERO -// RUN: %t a b - -int main(int argc, char **argv) { - // CHECK-MINUS-ONE: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value -1 - // CHECK-ZERO: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value 0 - int arr[argc - 2]; - return 0; -} diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp deleted file mode 100644 index 8106ae47ee4f..000000000000 --- a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t -// RUN: %t 2>&1 | FileCheck %s - -#include <stdint.h> - -void f() {} - -void g(int x) {} - -int main(void) { - // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)' - // CHECK-NEXT: function.cpp:6: note: f() defined here - reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42); - - // CHECK-NOT: runtime error: call to function g - reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42); -} diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg deleted file mode 100644 index 27c61a34387c..000000000000 --- a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg +++ /dev/null @@ -1,3 +0,0 @@ -# The function type checker is only supported on x86 and x86_64 for now. -if config.root.host_arch not in ['x86', 'x86_64']: - config.unsupported = True diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp deleted file mode 100644 index 9b0b9a1197c0..000000000000 --- a/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t -// RUN: %t l0 && %t s0 && %t r0 && %t m0 && %t f0 && %t n0 -// RUN: %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace -// RUN: %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE -// RUN: %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE -// RUN: %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER -// RUN: %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN -// RUN: %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW - -#include <new> - -struct S { - S() {} - int f() { return 0; } - int k; -}; - -int main(int, char **argv) { - char c[] __attribute__((aligned(8))) = { 0, 0, 0, 0, 1, 2, 3, 4, 5 }; - - // Pointer value may be unspecified here, but behavior is not undefined. - int *p = (int*)&c[4 + argv[1][1] - '0']; - S *s = (S*)p; - - (void)*p; // ok! - - switch (argv[1][0]) { - case 'l': - // CHECK-LOAD: misaligned.cpp:[[@LINE+4]]:12: runtime error: load of misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment - // CHECK-LOAD-NEXT: [[PTR]]: note: pointer points here - // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-LOAD-NEXT: {{^ \^}} - return *p && 0; - - case 's': - // CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment - // CHECK-STORE-NEXT: [[PTR]]: note: pointer points here - // CHECK-STORE-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-STORE-NEXT: {{^ \^}} - *p = 1; - break; - - case 'r': - // CHECK-REFERENCE: misaligned.cpp:[[@LINE+4]]:15: runtime error: reference binding to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment - // CHECK-REFERENCE-NEXT: [[PTR]]: note: pointer points here - // CHECK-REFERENCE-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-REFERENCE-NEXT: {{^ \^}} - {int &r = *p;} - break; - - case 'm': - // CHECK-MEMBER: misaligned.cpp:[[@LINE+4]]:15: runtime error: member access within misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment - // CHECK-MEMBER-NEXT: [[PTR]]: note: pointer points here - // CHECK-MEMBER-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-MEMBER-NEXT: {{^ \^}} - return s->k && 0; - - case 'f': - // CHECK-MEMFUN: misaligned.cpp:[[@LINE+4]]:12: runtime error: member call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment - // CHECK-MEMFUN-NEXT: [[PTR]]: note: pointer points here - // CHECK-MEMFUN-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-MEMFUN-NEXT: {{^ \^}} - return s->f() && 0; - - case 'n': - // FIXME: Provide a better source location here. - // CHECK-NEW: misaligned{{.*}}+0x{{[0-9a-f]*}}): runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment - // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here - // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}} - // CHECK-NEW-NEXT: {{^ \^}} - return (new (s) S)->k && 0; - } -} diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp deleted file mode 100644 index 79726924d213..000000000000 --- a/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// RUN: %clangxx -fsanitize=null %s -O3 -o %t -// RUN: %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD -// RUN: %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE -// RUN: %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE -// RUN: %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER -// RUN: %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN - -struct S { - int f() { return 0; } - int k; -}; - -int main(int, char **argv) { - int *p = 0; - S *s = 0; - - (void)*p; // ok! - - switch (argv[1][0]) { - case 'l': - // CHECK-LOAD: null.cpp:22:12: runtime error: load of null pointer of type 'int' - return *p; - case 's': - // CHECK-STORE: null.cpp:25:5: runtime error: store to null pointer of type 'int' - *p = 1; - break; - case 'r': - // CHECK-REFERENCE: null.cpp:29:15: runtime error: reference binding to null pointer of type 'int' - {int &r = *p;} - break; - case 'm': - // CHECK-MEMBER: null.cpp:33:15: runtime error: member access within null pointer of type 'S' - return s->k; - case 'f': - // CHECK-MEMFUN: null.cpp:36:12: runtime error: member call on null pointer of type 'S' - return s->f(); - } -} diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp deleted file mode 100644 index 9095f7279a66..000000000000 --- a/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// RUN: %clangxx -fsanitize=vptr %s -O3 -o %t -// RUN: %t rT && %t mT && %t fT && %t cT -// RUN: %t rU && %t mU && %t fU && %t cU -// RUN: %t rS && %t rV && %t oV -// RUN: %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace -// RUN: %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace -// RUN: %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace -// RUN: %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace -// RUN: %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace -// RUN: %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace -// RUN: %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace -// RUN: %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace - -// FIXME: This test produces linker errors on Darwin. -// XFAIL: darwin - -struct S { - S() : a(0) {} - ~S() {} - int a; - int f() { return 0; } - virtual int v() { return 0; } -}; - -struct T : S { - T() : b(0) {} - int b; - int g() { return 0; } - virtual int v() { return 1; } -}; - -struct U : S, T { virtual int v() { return 2; } }; - -int main(int, char **argv) { - T t; - (void)t.a; - (void)t.b; - (void)t.f(); - (void)t.g(); - (void)t.v(); - (void)t.S::v(); - - U u; - (void)u.T::a; - (void)u.b; - (void)u.T::f(); - (void)u.g(); - (void)u.v(); - (void)u.T::v(); - (void)((T&)u).S::v(); - - T *p = 0; - char Buffer[sizeof(U)] = {}; - switch (argv[1][1]) { - case '0': - p = reinterpret_cast<T*>(Buffer); - break; - case 'S': - p = reinterpret_cast<T*>(new S); - break; - case 'T': - p = new T; - break; - case 'U': - p = new U; - break; - case 'V': - p = reinterpret_cast<T*>(new U); - break; - } - - switch (argv[1][0]) { - case 'r': - // Binding a reference to storage of appropriate size and alignment is OK. - {T &r = *p;} - break; - - case 'm': - // CHECK-MEMBER: vptr.cpp:[[@LINE+5]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' - // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']] - // CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }} - // CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} - // CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]] - return p->b; - - // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' - // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr - // CHECK-NULL-MEMBER-NEXT: {{^ .. .. .. .. 00 00 00 00 00 00 00 00 }} - // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} - // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}} - - case 'f': - // CHECK-MEMFUN: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' - // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']] - // CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }} - // CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} - // CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]] - return p->g(); - - case 'o': - // CHECK-OFFSET: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U' - // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']] - // CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }} - // CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}} - // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]] - return reinterpret_cast<U*>(p)->v() - 2; - - case 'c': - // CHECK-DOWNCAST: vptr.cpp:[[@LINE+5]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' - // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']] - // CHECK-DOWNCAST-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }} - // CHECK-DOWNCAST-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} - // CHECK-DOWNCAST-NEXT: {{^ vptr for}} [[DYN_TYPE]] - static_cast<T*>(reinterpret_cast<S*>(p)); - return 0; - } -} diff --git a/lib/ubsan/lit_tests/UbsanConfig/lit.cfg b/lib/ubsan/lit_tests/UbsanConfig/lit.cfg deleted file mode 100644 index fcc93035c600..000000000000 --- a/lib/ubsan/lit_tests/UbsanConfig/lit.cfg +++ /dev/null @@ -1,23 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -ubsan_lit_tests_dir = get_required_attr(config, "ubsan_lit_tests_dir") -ubsan_lit_cfg = os.path.join(ubsan_lit_tests_dir, "lit.common.cfg") -lit_config.load_config(config, ubsan_lit_cfg) - -config.name = 'UndefinedBehaviorSanitizer-Standalone' - -# Define %clang and %clangxx substitutions to use in test RUN lines. -config.substitutions.append( ("%clang ", (" " + config.clang + " ")) ) -config.substitutions.append( ("%clangxx ", (" " + config.clang + - " --driver-mode=g++ ")) ) diff --git a/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in b/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in deleted file mode 100644 index c08fc30d0042..000000000000 --- a/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in +++ /dev/null @@ -1,8 +0,0 @@ -# Load common config for all compiler-rt lit tests. -lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") - -# Tool-specific config options. -config.ubsan_lit_tests_dir = "@UBSAN_LIT_TESTS_DIR@" - -# Load tool-specific config that would do the real work. -lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/UbsanConfig/lit.cfg") diff --git a/lib/ubsan/lit_tests/lit.common.cfg b/lib/ubsan/lit_tests/lit.common.cfg deleted file mode 100644 index 23c85e9fa065..000000000000 --- a/lib/ubsan/lit_tests/lit.common.cfg +++ /dev/null @@ -1,31 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -# Setup source root. -ubsan_lit_tests_dir = get_required_attr(config, 'ubsan_lit_tests_dir') -config.test_source_root = os.path.join(ubsan_lit_tests_dir, 'TestCases') - -def DisplayNoConfigMessage(): - lit_config.fatal("No site specific configuration available! " + - "Try running your test from the build tree or running " + - "make check-ubsan") - -# Default test suffixes. -config.suffixes = ['.c', '.cc', '.cpp'] - -# UndefinedBehaviorSanitizer tests are currently supported on -# Linux and Darwin only. -if config.host_os not in ['Linux', 'Darwin']: - config.unsupported = True - -config.pipefail = False diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index fa643658ea36..76ce2bd39996 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -12,15 +12,60 @@ //===----------------------------------------------------------------------===// #include "ubsan_diag.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_libc.h" +#include "ubsan_init.h" +#include "ubsan_flags.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_stacktrace_printer.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include <stdio.h> using namespace __ubsan; +static void MaybePrintStackTrace(uptr pc, uptr bp) { + // We assume that flags are already parsed: InitIfNecessary + // will definitely be called when we print the first diagnostics message. + if (!flags()->print_stacktrace) + return; + // We can only use slow unwind, as we don't have any information about stack + // top/bottom. + // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and + // fetch stack top/bottom information if we have it (e.g. if we're running + // under ASan). + if (StackTrace::WillUseFastUnwind(false)) + return; + BufferedStackTrace stack; + stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false); + stack.Print(); +} + +static void MaybeReportErrorSummary(Location Loc) { + if (!common_flags()->print_summary) + return; + // Don't try to unwind the stack trace in UBSan summaries: just use the + // provided location. + if (Loc.isSourceLocation()) { + SourceLocation SLoc = Loc.getSourceLocation(); + if (!SLoc.isInvalid()) { + ReportErrorSummary("undefined-behavior", SLoc.getFilename(), + SLoc.getLine(), ""); + return; + } + } + ReportErrorSummary("undefined-behavior"); +} + +namespace { +class Decorator : public SanitizerCommonDecorator { + public: + Decorator() : SanitizerCommonDecorator() {} + const char *Highlight() const { return Green(); } + const char *EndHighlight() const { return Default(); } + const char *Note() const { return Black(); } + const char *EndNote() const { return Default(); } +}; +} + Location __ubsan::getCallerLocation(uptr CallerLoc) { if (!CallerLoc) return Location(); @@ -32,19 +77,28 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) { Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) { if (!Loc) return Location(); + InitIfNecessary(); + + SymbolizedStack *Frames = Symbolizer::GetOrInit()->SymbolizePC(Loc); + const AddressInfo &Info = Frames->info; - AddressInfo Info; - if (!Symbolizer::GetOrInit()->SymbolizeCode(Loc, &Info, 1) || - !Info.module || !*Info.module) + if (!Info.module) { + Frames->ClearAll(); return Location(Loc); + } if (FName && Info.function) - *FName = Info.function; + *FName = internal_strdup(Info.function); - if (!Info.file) - return ModuleLocation(Info.module, Info.module_offset); + if (!Info.file) { + ModuleLocation MLoc(internal_strdup(Info.module), Info.module_offset); + Frames->ClearAll(); + return MLoc; + } - return SourceLocation(Info.file, Info.line, Info.column); + SourceLocation SLoc(internal_strdup(Info.file), Info.line, Info.column); + Frames->ClearAll(); + return SLoc; } Diag &Diag::operator<<(const TypeDescriptor &V) { @@ -84,14 +138,16 @@ static void renderLocation(Location Loc) { if (SLoc.isInvalid()) LocBuffer.append("<unknown>"); else - PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(), - SLoc.getColumn()); + RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(), + SLoc.getColumn(), common_flags()->strip_path_prefix); break; } - case Location::LK_Module: - PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(), - Loc.getModuleLocation().getOffset()); + case Location::LK_Module: { + ModuleLocation MLoc = Loc.getModuleLocation(); + RenderModuleLocation(&LocBuffer, MLoc.getModuleName(), MLoc.getOffset(), + common_flags()->strip_path_prefix); break; + } case Location::LK_Memory: LocBuffer.append("%p", Loc.getMemoryLocation()); break; @@ -164,36 +220,49 @@ static Range *upperBound(MemoryLocation Loc, Range *Ranges, return Best; } +static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) { + return (LHS < RHS) ? 0 : LHS - RHS; +} + +static inline uptr addNoOverflow(uptr LHS, uptr RHS) { + const uptr Limit = (uptr)-1; + return (LHS > Limit - RHS) ? Limit : LHS + RHS; +} + /// Render a snippet of the address space near a location. -static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor, - MemoryLocation Loc, +static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc, Range *Ranges, unsigned NumRanges, const Diag::Arg *Args) { - const unsigned BytesToShow = 32; - const unsigned MinBytesNearLoc = 4; - // Show at least the 8 bytes surrounding Loc. - MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc; + const unsigned MinBytesNearLoc = 4; + MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); + MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); + MemoryLocation OrigMin = Min; for (unsigned I = 0; I < NumRanges; ++I) { Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); } // If we have too many interesting bytes, prefer to show bytes after Loc. + const unsigned BytesToShow = 32; if (Max - Min > BytesToShow) - Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc); - Max = Min + BytesToShow; + Min = __sanitizer::Min(Max - BytesToShow, OrigMin); + Max = addNoOverflow(Min, BytesToShow); + + if (!IsAccessibleMemoryRange(Min, Max - Min)) { + Printf("<memory cannot be printed>\n"); + return; + } // Emit data. for (uptr P = Min; P != Max; ++P) { - // FIXME: Check that the address is readable before printing it. unsigned char C = *reinterpret_cast<const unsigned char*>(P); Printf("%s%02x", (P % 8 == 0) ? " " : " ", C); } Printf("\n"); // Emit highlights. - Printf(Decor.Green()); + Printf(Decor.Highlight()); Range *InRange = upperBound(Min, Ranges, NumRanges); for (uptr P = Min; P != Max; ++P) { char Pad = ' ', Byte = ' '; @@ -208,7 +277,7 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor, char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 }; Printf((P % 8 == 0) ? Buffer : &Buffer[1]); } - Printf("%s\n", Decor.Default()); + Printf("%s\n", Decor.EndHighlight()); // Go over the line again, and print names for the ranges. InRange = 0; @@ -246,8 +315,9 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor, } Diag::~Diag() { - __sanitizer::AnsiColorDecorator Decor(PrintsToTty()); - SpinMutexLock l(&CommonSanitizerReportMutex); + // All diagnostics should be printed under report mutex. + CommonSanitizerReportMutex.CheckLocked(); + Decorator Decor; Printf(Decor.Bold()); renderLocation(Loc); @@ -255,11 +325,11 @@ Diag::~Diag() { switch (Level) { case DL_Error: Printf("%s runtime error: %s%s", - Decor.Red(), Decor.Default(), Decor.Bold()); + Decor.Warning(), Decor.EndWarning(), Decor.Bold()); break; case DL_Note: - Printf("%s note: %s", Decor.Black(), Decor.Default()); + Printf("%s note: %s", Decor.Note(), Decor.EndNote()); break; } @@ -271,3 +341,26 @@ Diag::~Diag() { renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); } + +ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc) + : Opts(Opts), SummaryLoc(SummaryLoc) { + InitIfNecessary(); + CommonSanitizerReportMutex.Lock(); +} + +ScopedReport::~ScopedReport() { + MaybePrintStackTrace(Opts.pc, Opts.bp); + MaybeReportErrorSummary(SummaryLoc); + CommonSanitizerReportMutex.Unlock(); + if (Opts.DieAfterReport || flags()->halt_on_error) + Die(); +} + +bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) { + Suppression *s; + // If .preinit_array is not used, it is possible that the UBSan runtime is not + // initialized. + if (!SANITIZER_CAN_USE_PREINIT_ARRAY) + InitIfNecessary(); + return SuppressionContext::Get()->Match(Str, Type, &s); +} diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 54d15a0cc1ba..296ec0d3f61a 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -14,6 +14,8 @@ #define UBSAN_DIAG_H #include "ubsan_value.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_suppressions.h" namespace __ubsan { @@ -203,6 +205,33 @@ public: Diag &operator<<(const Range &R) { return AddRange(R); } }; +struct ReportOptions { + /// If DieAfterReport is specified, UBSan will terminate the program after the + /// report is printed. + bool DieAfterReport; + /// pc/bp are used to unwind the stack trace. + uptr pc; + uptr bp; +}; + +#define GET_REPORT_OPTIONS(die_after_report) \ + GET_CALLER_PC_BP; \ + ReportOptions Opts = {die_after_report, pc, bp} + +/// \brief Instantiate this class before printing diagnostics in the error +/// report. This class ensures that reports from different threads and from +/// different sanitizers won't be mixed. +class ScopedReport { + ReportOptions Opts; + Location SummaryLoc; + +public: + ScopedReport(ReportOptions Opts, Location SummaryLoc); + ~ScopedReport(); +}; + +bool MatchSuppression(const char *Str, SuppressionType Type); + } // namespace __ubsan #endif // UBSAN_DIAG_H diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc new file mode 100644 index 000000000000..eda11f1b265c --- /dev/null +++ b/lib/ubsan/ubsan_flags.cc @@ -0,0 +1,63 @@ +//===-- ubsan_flags.cc ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Runtime flags for UndefinedBehaviorSanitizer. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flags.h" + +namespace __ubsan { + +static const char *MaybeCallUbsanDefaultOptions() { + return (&__ubsan_default_options) ? __ubsan_default_options() : ""; +} + +void InitializeCommonFlags() { + CommonFlags *cf = common_flags(); + SetCommonFlagsDefaults(cf); + cf->print_summary = false; + // Override from user-specified string. + ParseCommonFlagsFromString(cf, MaybeCallUbsanDefaultOptions()); + // Override from environment variable. + ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS")); +} + +Flags ubsan_flags; + +static void ParseFlagsFromString(Flags *f, const char *str) { + if (!str) + return; + ParseFlag(str, &f->halt_on_error, "halt_on_error", + "Crash the program after printing the first error report"); + ParseFlag(str, &f->print_stacktrace, "print_stacktrace", + "Include full stacktrace into an error report"); +} + +void InitializeFlags() { + Flags *f = flags(); + // Default values. + f->halt_on_error = false; + f->print_stacktrace = false; + // Override from user-specified string. + ParseFlagsFromString(f, MaybeCallUbsanDefaultOptions()); + // Override from environment variable. + ParseFlagsFromString(f, GetEnv("UBSAN_OPTIONS")); +} + +} // namespace __ubsan + +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char *__ubsan_default_options() { return ""; } +} // extern "C" +#endif diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h new file mode 100644 index 000000000000..c496469f5f41 --- /dev/null +++ b/lib/ubsan/ubsan_flags.h @@ -0,0 +1,40 @@ +//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Runtime flags for UndefinedBehaviorSanitizer. +// +//===----------------------------------------------------------------------===// +#ifndef UBSAN_FLAGS_H +#define UBSAN_FLAGS_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __ubsan { + +struct Flags { + bool halt_on_error; + bool print_stacktrace; +}; + +extern Flags ubsan_flags; +inline Flags *flags() { return &ubsan_flags; } + +void InitializeCommonFlags(); +void InitializeFlags(); + +} // namespace __ubsan + +extern "C" { +// Users may provide their own implementation of __ubsan_default_options to +// override the default flag values. +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char *__ubsan_default_options(); +} // extern "C" + +#endif // UBSAN_FLAGS_H diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index d55643143295..a0ecff943592 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -19,23 +19,35 @@ using namespace __sanitizer; using namespace __ubsan; +static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) { + // If source location is already acquired, we don't need to print an error + // report for the second time. However, if we're in an unrecoverable handler, + // it's possible that location was required by concurrently running thread. + // In this case, we should continue the execution to ensure that any of + // threads will grab the report mutex and print the report before + // crashing the program. + return SLoc.isDisabled() && !Opts.DieAfterReport; +} + namespace __ubsan { - const char *TypeCheckKinds[] = { +const char *TypeCheckKinds[] = { "load of", "store to", "reference binding to", "member access within", - "member call on", "constructor call on", "downcast of", "downcast of" - }; + "member call on", "constructor call on", "downcast of", "downcast of", + "upcast of", "cast to virtual base of"}; } static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, - Location FallbackLoc) { + Location FallbackLoc, ReportOptions Opts) { Location Loc = Data->Loc.acquire(); - // Use the SourceLocation from Data to track deduplication, even if 'invalid' - if (Loc.getSourceLocation().isDisabled()) + if (ignoreReport(Loc.getSourceLocation(), Opts)) return; + if (Data->Loc.isInvalid()) Loc = FallbackLoc; + ScopedReport R(Opts, Loc); + if (!Pointer) Diag(Loc, DL_Error, "%0 null pointer of type %1") << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; @@ -51,70 +63,59 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, if (Pointer) Diag(Pointer, DL_Note, "pointer points here"); } + void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, ValueHandle Pointer) { - handleTypeMismatchImpl(Data, Pointer, getCallerLocation()); + GET_REPORT_OPTIONS(false); + handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); } void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, ValueHandle Pointer) { - handleTypeMismatchImpl(Data, Pointer, getCallerLocation()); + GET_REPORT_OPTIONS(true); + handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); Die(); } /// \brief Common diagnostic emission for various forms of integer overflow. -template<typename T> static void HandleIntegerOverflow(OverflowData *Data, - ValueHandle LHS, - const char *Operator, - T RHS) { +template <typename T> +static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, + const char *Operator, T RHS, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + 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; } -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) { +#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \ + void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ + ValueHandle RHS) { \ + GET_REPORT_OPTIONS(abort); \ + handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ + if (abort) Die(); \ + } + +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) +UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) + +static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + if (Data->Type.isSignedIntegerTy()) Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1; " @@ -125,18 +126,27 @@ void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, "negation of %0 cannot be represented in type %1") << Value(Data->Type, OldVal) << Data->Type; } + +void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, + ValueHandle OldVal) { + GET_REPORT_OPTIONS(false); + handleNegateOverflowImpl(Data, OldVal, Opts); +} void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, ValueHandle OldVal) { - __ubsan_handle_negate_overflow(Data, OldVal); + GET_REPORT_OPTIONS(true); + handleNegateOverflowImpl(Data, OldVal, Opts); Die(); } -void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, - ValueHandle LHS, ValueHandle RHS) { +static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, + ValueHandle RHS, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + Value LHSVal(Data->Type, LHS); Value RHSVal(Data->Type, RHS); if (RHSVal.isMinusOne()) @@ -146,20 +156,29 @@ void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, else Diag(Loc, DL_Error, "division by zero"); } + +void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, + ValueHandle LHS, ValueHandle RHS) { + GET_REPORT_OPTIONS(false); + handleDivremOverflowImpl(Data, LHS, RHS, Opts); +} void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, ValueHandle LHS, ValueHandle RHS) { - __ubsan_handle_divrem_overflow(Data, LHS, RHS); + GET_REPORT_OPTIONS(true); + handleDivremOverflowImpl(Data, LHS, RHS, Opts); Die(); } -void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, - ValueHandle LHS, - ValueHandle RHS) { +static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, + ValueHandle LHS, ValueHandle RHS, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + Value LHSVal(Data->LHSType, LHS); Value RHSVal(Data->RHSType, RHS); if (RHSVal.isNegative()) @@ -175,107 +194,219 @@ void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, "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(ShiftOutOfBoundsData *Data, + ValueHandle LHS, + ValueHandle RHS) { + GET_REPORT_OPTIONS(false); + handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); +} void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( ShiftOutOfBoundsData *Data, ValueHandle LHS, ValueHandle RHS) { - __ubsan_handle_shift_out_of_bounds(Data, LHS, RHS); + GET_REPORT_OPTIONS(true); + handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); Die(); } -void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, - ValueHandle Index) { +static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + Value IndexVal(Data->IndexType, Index); Diag(Loc, DL_Error, "index %0 out of bounds for type %1") << IndexVal << Data->ArrayType; } + +void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, + ValueHandle Index) { + GET_REPORT_OPTIONS(false); + handleOutOfBoundsImpl(Data, Index, Opts); +} void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, ValueHandle Index) { - __ubsan_handle_out_of_bounds(Data, Index); + GET_REPORT_OPTIONS(true); + handleOutOfBoundsImpl(Data, Index, Opts); Die(); } -void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { +static void handleBuiltinUnreachableImpl(UnreachableData *Data, + ReportOptions Opts) { + ScopedReport R(Opts, Data->Loc); Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); +} + +void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { + GET_REPORT_OPTIONS(true); + handleBuiltinUnreachableImpl(Data, Opts); Die(); } -void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { +static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { + ScopedReport R(Opts, Data->Loc); Diag(Data->Loc, DL_Error, "execution reached the end of a value-returning function " "without returning a value"); +} + +void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { + GET_REPORT_OPTIONS(true); + handleMissingReturnImpl(Data, Opts); Die(); } -void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, - ValueHandle Bound) { +static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + 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(VLABoundData *Data, + ValueHandle Bound) { + GET_REPORT_OPTIONS(false); + handleVLABoundNotPositive(Data, Bound, Opts); +} void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, - ValueHandle Bound) { - __ubsan_handle_vla_bound_not_positive(Data, Bound); + ValueHandle Bound) { + GET_REPORT_OPTIONS(true); + handleVLABoundNotPositive(Data, Bound, Opts); Die(); } +static void handleFloatCastOverflow(FloatCastOverflowData *Data, + ValueHandle From, ReportOptions Opts) { + // TODO: Add deduplication once a SourceLocation is generated for this check. + Location Loc = getCallerLocation(); + ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, + "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(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; + GET_REPORT_OPTIONS(false); + handleFloatCastOverflow(Data, From, Opts); } -void __ubsan::__ubsan_handle_float_cast_overflow_abort( - FloatCastOverflowData *Data, - ValueHandle From) { - Diag(getCallerLocation(), DL_Error, - "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) { + GET_REPORT_OPTIONS(true); + handleFloatCastOverflow(Data, From, Opts); Die(); } -void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, - ValueHandle Val) { +static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, + ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - if (Loc.isDisabled()) + if (ignoreReport(Loc, Opts)) return; + ScopedReport R(Opts, Loc); + Diag(Loc, DL_Error, "load of value %0, which is not a valid value for type %1") << Value(Data->Type, Val) << Data->Type; } + +void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, + ValueHandle Val) { + GET_REPORT_OPTIONS(false); + handleLoadInvalidValue(Data, Val, Opts); +} void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, ValueHandle Val) { - __ubsan_handle_load_invalid_value(Data, Val); + GET_REPORT_OPTIONS(true); + handleLoadInvalidValue(Data, Val, Opts); Die(); } -void __ubsan::__ubsan_handle_function_type_mismatch( - FunctionTypeMismatchData *Data, - ValueHandle Function) { +static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, + ValueHandle Function, + ReportOptions Opts) { const char *FName = "(unknown)"; Location Loc = getFunctionLocation(Function, &FName); + ScopedReport R(Opts, Loc); + Diag(Data->Loc, DL_Error, "call to function %0 through pointer to incorrect function type %1") << FName << Data->Type; Diag(Loc, DL_Note, "%0 defined here") << FName; } +void +__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, + ValueHandle Function) { + GET_REPORT_OPTIONS(false); + handleFunctionTypeMismatch(Data, Function, Opts); +} + void __ubsan::__ubsan_handle_function_type_mismatch_abort( - FunctionTypeMismatchData *Data, - ValueHandle Function) { - __ubsan_handle_function_type_mismatch(Data, Function); + FunctionTypeMismatchData *Data, ValueHandle Function) { + GET_REPORT_OPTIONS(true); + handleFunctionTypeMismatch(Data, Function, Opts); + Die(); +} + +static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + if (ignoreReport(Loc, Opts)) + return; + + ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "null pointer returned from function declared to never " + "return null"); + if (!Data->AttrLoc.isInvalid()) + Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); +} + +void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { + GET_REPORT_OPTIONS(false); + handleNonNullReturn(Data, Opts); +} + +void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { + GET_REPORT_OPTIONS(true); + handleNonNullReturn(Data, Opts); + Die(); +} + +static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + if (ignoreReport(Loc, Opts)) + return; + + ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " + "never be null") << Data->ArgIndex; + if (!Data->AttrLoc.isInvalid()) + Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); +} + +void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { + GET_REPORT_OPTIONS(false); + handleNonNullArg(Data, Opts); +} + +void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { + GET_REPORT_OPTIONS(true); + handleNonNullArg(Data, Opts); Die(); } diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 14e6f04c2a1b..87149f259607 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -24,10 +24,14 @@ struct TypeMismatchData { unsigned char TypeCheckKind; }; +#define UNRECOVERABLE(checkname, ...) \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \ + void __ubsan_handle_ ## checkname( __VA_ARGS__ ); + #define RECOVERABLE(checkname, ...) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE \ void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \ - extern "C" SANITIZER_INTERFACE_ATTRIBUTE \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \ void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ ); /// \brief Handle a runtime type check failure, caused by either a misaligned @@ -81,11 +85,9 @@ struct UnreachableData { }; /// \brief Handle a __builtin_unreachable which is reached. -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __ubsan_handle_builtin_unreachable(UnreachableData *Data); +UNRECOVERABLE(builtin_unreachable, UnreachableData *Data) /// \brief Handle reaching the end of a value-returning function. -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __ubsan_handle_missing_return(UnreachableData *Data); +UNRECOVERABLE(missing_return, UnreachableData *Data) struct VLABoundData { SourceLocation Loc; @@ -121,6 +123,23 @@ RECOVERABLE(function_type_mismatch, FunctionTypeMismatchData *Data, ValueHandle Val) +struct NonNullReturnData { + SourceLocation Loc; + SourceLocation AttrLoc; +}; + +/// \brief Handle returning null from function with returns_nonnull attribute. +RECOVERABLE(nonnull_return, NonNullReturnData *Data) + +struct NonNullArgData { + SourceLocation Loc; + SourceLocation AttrLoc; + int ArgIndex; +}; + +/// \brief Handle passing null pointer to function with nonnull attribute. +RECOVERABLE(nonnull_arg, NonNullArgData *Data) + } #endif // UBSAN_HANDLERS_H diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index b6cddefeb4f4..5704c1e6342d 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -18,6 +18,7 @@ #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_suppressions.h" using namespace __sanitizer; using namespace __ubsan; @@ -28,47 +29,54 @@ namespace __ubsan { static void HandleDynamicTypeCacheMiss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, - bool Abort) { + ReportOptions Opts) { if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash)) // Just a cache miss. The type matches after all. return; + // Check if error report should be suppressed. + DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); + if (DTI.isValid() && + MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck)) + return; + SourceLocation Loc = Data->Loc.acquire(); if (Loc.isDisabled()) return; + ScopedReport R(Opts, Loc); + Diag(Loc, DL_Error, "%0 address %1 which does not point to an object of type %2") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; // If possible, say what type it actually points to. - DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); if (!DTI.isValid()) Diag(Pointer, DL_Note, "object has invalid vptr") - << MangledName(DTI.getMostDerivedTypeName()) - << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); + << MangledName(DTI.getMostDerivedTypeName()) + << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); else if (!DTI.getOffset()) Diag(Pointer, DL_Note, "object is of type %0") - << MangledName(DTI.getMostDerivedTypeName()) - << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); + << MangledName(DTI.getMostDerivedTypeName()) + << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); else // FIXME: Find the type at the specified offset, and include that // in the note. Diag(Pointer - DTI.getOffset(), DL_Note, "object is base class subobject at offset %0 within object of type %1") - << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName()) - << MangledName(DTI.getSubobjectTypeName()) - << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1"); - - if (Abort) - Die(); + << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName()) + << MangledName(DTI.getSubobjectTypeName()) + << Range(Pointer, Pointer + sizeof(uptr), + "vptr for %2 base class of %1"); } void __ubsan::__ubsan_handle_dynamic_type_cache_miss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { - HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false); + GET_REPORT_OPTIONS(false); + HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { - HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true); + GET_REPORT_OPTIONS(true); + HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc new file mode 100644 index 000000000000..6080e304c122 --- /dev/null +++ b/lib/ubsan/ubsan_init.cc @@ -0,0 +1,61 @@ +//===-- ubsan_init.cc -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Initialization of UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_init.h" +#include "ubsan_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_suppressions.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +using namespace __ubsan; + +static bool ubsan_inited; + +void __ubsan::InitIfNecessary() { +#if !SANITIZER_CAN_USE_PREINIT_ARRAY + // No need to lock mutex if we're initializing from preinit array. + static StaticSpinMutex init_mu; + SpinMutexLock l(&init_mu); +#endif + if (LIKELY(ubsan_inited)) + return; + if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) { + // WARNING: If this condition holds, then either UBSan runs in a standalone + // mode, or initializer for another sanitizer hasn't run yet. In a latter + // case, another sanitizer will overwrite "SanitizerToolName" and reparse + // common flags. It means, that we are not allowed to *use* common flags + // in this function. + SanitizerToolName = "UndefinedBehaviorSanitizer"; + InitializeCommonFlags(); + } + // Initialize UBSan-specific flags. + InitializeFlags(); + SuppressionContext::InitIfNecessary(); + ubsan_inited = true; +} + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), used)) +void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary; +#else +// Use a dynamic initializer. +class UbsanInitializer { + public: + UbsanInitializer() { + InitIfNecessary(); + } +}; +static UbsanInitializer ubsan_initializer; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h new file mode 100644 index 000000000000..18356cfca617 --- /dev/null +++ b/lib/ubsan/ubsan_init.h @@ -0,0 +1,24 @@ +//===-- ubsan_init.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Initialization function for UBSan runtime. +// +//===----------------------------------------------------------------------===// +#ifndef UBSAN_INIT_H +#define UBSAN_INIT_H + +namespace __ubsan { + +// NOTE: This function might take a lock (if .preinit_array initialization is +// not used). It's generally a bad idea to call it on a fast path. +void InitIfNecessary(); + +} // namespace __ubsan + +#endif // UBSAN_INIT_H diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc index a388bcc6d72e..808a4332d01f 100644 --- a/lib/ubsan/ubsan_type_hash.cc +++ b/lib/ubsan/ubsan_type_hash.cc @@ -115,7 +115,8 @@ __ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize]; /// \brief Determine whether \p Derived has a \p Base base class subobject at /// offset \p Offset. -static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, +static bool isDerivedFromAtOffset(sptr Object, + const abi::__class_type_info *Derived, const abi::__class_type_info *Base, sptr Offset) { if (Derived->__type_name == Base->__type_name) @@ -123,7 +124,7 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, if (const abi::__si_class_type_info *SI = dynamic_cast<const abi::__si_class_type_info*>(Derived)) - return isDerivedFromAtOffset(SI->__base_type, Base, Offset); + return isDerivedFromAtOffset(Object, SI->__base_type, Base, Offset); const abi::__vmi_class_type_info *VTI = dynamic_cast<const abi::__vmi_class_type_info*>(Derived); @@ -138,13 +139,13 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, sptr OffsetHere = VTI->base_info[base].__offset_flags >> abi::__base_class_type_info::__offset_shift; if (VTI->base_info[base].__offset_flags & - abi::__base_class_type_info::__virtual_mask) - // For now, just punt on virtual bases and say 'yes'. - // FIXME: OffsetHere is the offset in the vtable of the virtual base - // offset. Read the vbase offset out of the vtable and use it. - return true; - if (isDerivedFromAtOffset(VTI->base_info[base].__base_type, - Base, Offset - OffsetHere)) + abi::__base_class_type_info::__virtual_mask) { + sptr VTable = *reinterpret_cast<const sptr *>(Object); + OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere); + } + if (isDerivedFromAtOffset(Object + OffsetHere, + VTI->base_info[base].__base_type, Base, + Offset - OffsetHere)) return true; } @@ -153,14 +154,15 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, /// \brief Find the derived-most dynamic base class of \p Derived at offset /// \p Offset. -static const abi::__class_type_info *findBaseAtOffset( - const abi::__class_type_info *Derived, sptr Offset) { +static const abi::__class_type_info * +findBaseAtOffset(sptr Object, const abi::__class_type_info *Derived, + sptr Offset) { if (!Offset) return Derived; if (const abi::__si_class_type_info *SI = dynamic_cast<const abi::__si_class_type_info*>(Derived)) - return findBaseAtOffset(SI->__base_type, Offset); + return findBaseAtOffset(Object, SI->__base_type, Offset); const abi::__vmi_class_type_info *VTI = dynamic_cast<const abi::__vmi_class_type_info*>(Derived); @@ -172,12 +174,13 @@ static const abi::__class_type_info *findBaseAtOffset( sptr OffsetHere = VTI->base_info[base].__offset_flags >> abi::__base_class_type_info::__offset_shift; if (VTI->base_info[base].__offset_flags & - abi::__base_class_type_info::__virtual_mask) - // FIXME: Can't handle virtual bases yet. - continue; - if (const abi::__class_type_info *Base = - findBaseAtOffset(VTI->base_info[base].__base_type, - Offset - OffsetHere)) + abi::__base_class_type_info::__virtual_mask) { + sptr VTable = *reinterpret_cast<const sptr *>(Object); + OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere); + } + if (const abi::__class_type_info *Base = findBaseAtOffset( + Object + OffsetHere, VTI->base_info[base].__base_type, + Offset - OffsetHere)) return Base; } @@ -229,7 +232,8 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { return false; abi::__class_type_info *Base = (abi::__class_type_info*)Type; - if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset)) + if (!isDerivedFromAtOffset(reinterpret_cast<sptr>(Object), Derived, Base, + -Vtable->Offset)) return false; // Success. Cache this result. @@ -243,8 +247,9 @@ __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) { if (!Vtable) return DynamicTypeInfo(0, 0, 0); const abi::__class_type_info *ObjectType = findBaseAtOffset( - static_cast<const abi::__class_type_info*>(Vtable->TypeInfo), - -Vtable->Offset); + reinterpret_cast<sptr>(Object), + static_cast<const abi::__class_type_info *>(Vtable->TypeInfo), + -Vtable->Offset); return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset, ObjectType ? ObjectType->__type_name : "<unknown>"); } diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc index 5d77350d0c40..ab74720f60cf 100644 --- a/lib/ubsan/ubsan_value.cc +++ b/lib/ubsan/ubsan_value.cc @@ -94,6 +94,7 @@ FloatMax Value::getFloatValue() const { switch (getType().getFloatBitWidth()) { case 64: return *reinterpret_cast<double*>(Val); case 80: return *reinterpret_cast<long double*>(Val); + case 96: return *reinterpret_cast<long double*>(Val); case 128: return *reinterpret_cast<long double*>(Val); } } diff --git a/lib/ubsan/ubsan_value.h b/lib/ubsan/ubsan_value.h index 54ed5ad1931f..a6810844049f 100644 --- a/lib/ubsan/ubsan_value.h +++ b/lib/ubsan/ubsan_value.h @@ -14,9 +14,9 @@ #ifndef UBSAN_VALUE_H #define UBSAN_VALUE_H -// For now, only support linux and darwin. Other platforms should be easy to -// add, and probably work as-is. -#if !defined(__linux__) && !defined(__APPLE__) +// For now, only support Linux, FreeBSD and Darwin. Other platforms should +// be easy to add, and probably work as-is. +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) #error "UBSan not supported for this platform!" #endif @@ -25,8 +25,8 @@ // FIXME: Move this out to a config header. #if __SIZEOF_INT128__ -typedef __int128 s128; -typedef unsigned __int128 u128; +__extension__ typedef __int128 s128; +__extension__ typedef unsigned __int128 u128; #define HAVE_INT128_T 1 #else #define HAVE_INT128_T 0 |