aboutsummaryrefslogtreecommitdiff
path: root/lib/ubsan
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
commitca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch)
tree9b19e801150082c33e9152275829a6ce90614b55 /lib/ubsan
parent8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff)
downloadsrc-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')
-rw-r--r--lib/ubsan/CMakeLists.txt27
-rw-r--r--lib/ubsan/lit_tests/AsanConfig/lit.cfg25
-rw-r--r--lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in9
-rw-r--r--lib/ubsan/lit_tests/CMakeLists.txt23
-rw-r--r--lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp99
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp32
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp10
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp15
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp14
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp12
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp22
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/shift.cpp37
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp31
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp32
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp19
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp31
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bool.cpp10
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp15
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp25
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/enum.cpp17
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp9
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp6
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/vla.c11
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp17
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg3
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp73
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp38
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp117
-rw-r--r--lib/ubsan/lit_tests/UbsanConfig/lit.cfg23
-rw-r--r--lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in8
-rw-r--r--lib/ubsan/lit_tests/lit.common.cfg31
-rw-r--r--lib/ubsan/ubsan_diag.cc151
-rw-r--r--lib/ubsan/ubsan_diag.h29
-rw-r--r--lib/ubsan/ubsan_flags.cc63
-rw-r--r--lib/ubsan/ubsan_flags.h40
-rw-r--r--lib/ubsan/ubsan_handlers.cc311
-rw-r--r--lib/ubsan/ubsan_handlers.h29
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc36
-rw-r--r--lib/ubsan/ubsan_init.cc61
-rw-r--r--lib/ubsan/ubsan_init.h24
-rw-r--r--lib/ubsan/ubsan_type_hash.cc47
-rw-r--r--lib/ubsan/ubsan_value.cc1
-rw-r--r--lib/ubsan/ubsan_value.h10
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