aboutsummaryrefslogtreecommitdiff
path: root/test/ubsan
diff options
context:
space:
mode:
Diffstat (limited to 'test/ubsan')
-rw-r--r--test/ubsan/CMakeLists.txt25
-rw-r--r--test/ubsan/TestCases/Float/cast-overflow.cpp134
-rw-r--r--test/ubsan/TestCases/Integer/add-overflow.cpp32
-rw-r--r--test/ubsan/TestCases/Integer/div-overflow.cpp10
-rw-r--r--test/ubsan/TestCases/Integer/div-zero.cpp15
-rw-r--r--test/ubsan/TestCases/Integer/incdec-overflow.cpp16
-rw-r--r--test/ubsan/TestCases/Integer/mul-overflow.cpp14
-rw-r--r--test/ubsan/TestCases/Integer/negate-overflow.cpp12
-rw-r--r--test/ubsan/TestCases/Integer/no-recover.cpp22
-rw-r--r--test/ubsan/TestCases/Integer/shift.cpp37
-rw-r--r--test/ubsan/TestCases/Integer/sub-overflow.cpp31
-rw-r--r--test/ubsan/TestCases/Integer/summary.cpp10
-rw-r--r--test/ubsan/TestCases/Integer/uadd-overflow.cpp32
-rw-r--r--test/ubsan/TestCases/Integer/uincdec-overflow.cpp16
-rw-r--r--test/ubsan/TestCases/Integer/umul-overflow.cpp19
-rw-r--r--test/ubsan/TestCases/Integer/usub-overflow.cpp31
-rw-r--r--test/ubsan/TestCases/Misc/bool.cpp10
-rw-r--r--test/ubsan/TestCases/Misc/bounds.cpp15
-rw-r--r--test/ubsan/TestCases/Misc/deduplication.cpp25
-rw-r--r--test/ubsan/TestCases/Misc/enum.cpp17
-rw-r--r--test/ubsan/TestCases/Misc/missing_return.cpp17
-rw-r--r--test/ubsan/TestCases/Misc/nonnull-arg.cpp58
-rw-r--r--test/ubsan/TestCases/Misc/nonnull.cpp15
-rw-r--r--test/ubsan/TestCases/Misc/unreachable.cpp6
-rw-r--r--test/ubsan/TestCases/Misc/vla.c11
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/function.cpp24
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg3
-rw-r--r--test/ubsan/TestCases/TypeCheck/misaligned.cpp105
-rw-r--r--test/ubsan/TestCases/TypeCheck/null.cpp38
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp19
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr.cpp166
-rw-r--r--test/ubsan/lit.common.cfg56
-rw-r--r--test/ubsan/lit.site.cfg.in8
33 files changed, 1049 insertions, 0 deletions
diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt
new file mode 100644
index 000000000000..1c0c92903298
--- /dev/null
+++ b/test/ubsan/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(UBSAN_LIT_TEST_MODE "Standalone")
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig/lit.site.cfg)
+set(UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig)
+
+if(COMPILER_RT_HAS_ASAN)
+ set(UBSAN_LIT_TEST_MODE "AddressSanitizer")
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg)
+ list(APPEND UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig)
+endif()
+
+set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND UBSAN_TEST_DEPS ubsan asan)
+endif()
+
+add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests"
+ ${UBSAN_TESTSUITES}
+ DEPENDS ${UBSAN_TEST_DEPS})
+set_target_properties(check-ubsan PROPERTIES FOLDER "UBSan unittests")
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
new file mode 100644
index 000000000000..22991e0a6c55
--- /dev/null
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -0,0 +1,134 @@
+// FIXME: run this (and other) UBSan tests in both 32- and 64-bit modes (?).
+// RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t
+// RUN: %run %t _
+// RUN: %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
+// RUN: %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1
+// RUN: %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2
+// RUN: %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3
+// RUN: %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4
+// RUN: %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5
+// RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
+// FIXME: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
+// FIXME: not %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
+// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
+
+// This test assumes float and double are IEEE-754 single- and double-precision.
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#if defined(__APPLE__)
+# include <machine/endian.h>
+# define BYTE_ORDER __DARWIN_BYTE_ORDER
+# define BIG_ENDIAN __DARWIN_BIG_ENDIAN
+# define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
+#elif defined(__FreeBSD__)
+# include <sys/endian.h>
+# define BYTE_ORDER _BYTE_ORDER
+# define BIG_ENDIAN _BIG_ENDIAN
+# define LITTLE_ENDIAN _LITTLE_ENDIAN
+#else
+# include <endian.h>
+# define BYTE_ORDER __BYTE_ORDER
+# define BIG_ENDIAN __BIG_ENDIAN
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif // __APPLE__
+#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'.
+#if BYTE_ORDER == LITTLE_ENDIAN
+ char InfVal[] = { 0x00, 0x00, 0x80, 0x7f };
+#else
+ char InfVal[] = { 0x7f, 0x80, 0x00, 0x00 };
+#endif
+ float Inf;
+ memcpy(&Inf, InfVal, 4);
+
+ // Build a 'NaN'.
+#if BYTE_ORDER == LITTLE_ENDIAN
+ char NaNVal[] = { 0x01, 0x00, 0x80, 0x7f };
+#else
+ char NaNVal[] = { 0x7f, 0x80, 0x00, 0x01 };
+#endif
+ 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'
+ volatile float f = -1.0;
+ volatile unsigned u = (unsigned)f;
+ return 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;
+ case '9':
+ volatile long double ld = 300.0;
+ // CHECK-9: runtime error: value 300 is outside the range of representable values of type 'char'
+ char c = ld;
+ return c;
+ }
+}
diff --git a/test/ubsan/TestCases/Integer/add-overflow.cpp b/test/ubsan/TestCases/Integer/add-overflow.cpp
new file mode 100644
index 000000000000..d3425828ec88
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/add-overflow.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx -DADD_I32 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
+// RUN: %clangxx -DADD_I64 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
+// RUN: %clangxx -DADD_I128 -fsanitize=signed-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/div-overflow.cpp b/test/ubsan/TestCases/Integer/div-overflow.cpp
new file mode 100644
index 000000000000..76dd60de45ce
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/div-overflow.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/div-zero.cpp b/test/ubsan/TestCases/Integer/div-zero.cpp
new file mode 100644
index 000000000000..9a223312e8e7
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/div-zero.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=1U %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=float-divide-by-zero -DDIVIDEND=1.5 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND='intmax(123)' %s -o %t && %run %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/test/ubsan/TestCases/Integer/incdec-overflow.cpp b/test/ubsan/TestCases/Integer/incdec-overflow.cpp
new file mode 100644
index 000000000000..fc7141c803d8
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/incdec-overflow.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -DOP=n++ -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=++n -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=m-- -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=--m -fsanitize=signed-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/mul-overflow.cpp b/test/ubsan/TestCases/Integer/mul-overflow.cpp
new file mode 100644
index 000000000000..20fece5f9fe2
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/mul-overflow.cpp
@@ -0,0 +1,14 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/negate-overflow.cpp b/test/ubsan/TestCases/Integer/negate-overflow.cpp
new file mode 100644
index 000000000000..bde0bdabb292
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/negate-overflow.cpp
@@ -0,0 +1,12 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECKS
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp
new file mode 100644
index 000000000000..575bd0a553fb
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/no-recover.cpp
@@ -0,0 +1,22 @@
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && not %run %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/test/ubsan/TestCases/Integer/shift.cpp b/test/ubsan/TestCases/Integer/shift.cpp
new file mode 100644
index 000000000000..e86fac8d574a
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/shift.cpp
@@ -0,0 +1,37 @@
+// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %run %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/test/ubsan/TestCases/Integer/sub-overflow.cpp b/test/ubsan/TestCases/Integer/sub-overflow.cpp
new file mode 100644
index 000000000000..15e64d951603
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/sub-overflow.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx -DSUB_I32 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
+// RUN: %clangxx -DSUB_I64 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
+// RUN: %clangxx -DSUB_I128 -fsanitize=signed-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp
new file mode 100644
index 000000000000..6e9aec63ca74
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/summary.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=integer %s -o %t && %t 2>&1 | FileCheck %s
+// REQUIRES: ubsan-asan
+
+#include <stdint.h>
+
+int main() {
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // CHECK: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Integer/uadd-overflow.cpp b/test/ubsan/TestCases/Integer/uadd-overflow.cpp
new file mode 100644
index 000000000000..7a96880fe636
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/uadd-overflow.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx -DADD_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
+// RUN: %clangxx -DADD_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
+// RUN: %clangxx -DADD_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/uincdec-overflow.cpp b/test/ubsan/TestCases/Integer/uincdec-overflow.cpp
new file mode 100644
index 000000000000..a236d21fcf1f
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/uincdec-overflow.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -DOP=n++ -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
+// RUN: %clangxx -DOP=++n -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
+// RUN: %clangxx -DOP=m-- -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s
+// RUN: %clangxx -DOP=--m -fsanitize=unsigned-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/umul-overflow.cpp b/test/ubsan/TestCases/Integer/umul-overflow.cpp
new file mode 100644
index 000000000000..ad5d1bd0d13c
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/umul-overflow.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Integer/usub-overflow.cpp b/test/ubsan/TestCases/Integer/usub-overflow.cpp
new file mode 100644
index 000000000000..e5de7de54eaa
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/usub-overflow.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx -DSUB_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
+// RUN: %clangxx -DSUB_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
+// RUN: %clangxx -DSUB_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %run %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/test/ubsan/TestCases/Misc/bool.cpp b/test/ubsan/TestCases/Misc/bool.cpp
new file mode 100644
index 000000000000..37ecea27c941
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/bool.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=bool %s -O3 -o %t && not %run %t 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/test/ubsan/TestCases/Misc/bounds.cpp b/test/ubsan/TestCases/Misc/bounds.cpp
new file mode 100644
index 000000000000..ffcac528be90
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/bounds.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=bounds %s -O3 -o %t
+// RUN: %run %t 0 0 0
+// RUN: %run %t 1 2 3
+// RUN: not --crash %run %t 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2
+// RUN: %run %t 0 3 0 2>&1 | FileCheck %s --check-prefix=CHECK-B-3
+// RUN: %run %t 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:[[@LINE-1]]:10: runtime error: index 2 out of bounds for type 'int [2][3][4]'
+ // CHECK-B-3: bounds.cpp:[[@LINE-2]]:10: runtime error: index 3 out of bounds for type 'int [3][4]'
+ // CHECK-C-4: bounds.cpp:[[@LINE-3]]:10: runtime error: index 4 out of bounds for type 'int [4]'
+}
diff --git a/test/ubsan/TestCases/Misc/deduplication.cpp b/test/ubsan/TestCases/Misc/deduplication.cpp
new file mode 100644
index 000000000000..7d7b0bd58c6e
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/deduplication.cpp
@@ -0,0 +1,25 @@
+// RUN: %clangxx -fsanitize=undefined %s -o %t && %run %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/test/ubsan/TestCases/Misc/enum.cpp b/test/ubsan/TestCases/Misc/enum.cpp
new file mode 100644
index 000000000000..49ac7c6bb187
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/enum.cpp
@@ -0,0 +1,17 @@
+// RUN: %clangxx -fsanitize=enum %s -O3 -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN
+// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %run %t
+// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && not %run %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/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp
new file mode 100644
index 000000000000..5d3d54de17dd
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/missing_return.cpp
@@ -0,0 +1,17 @@
+// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os-STACKTRACE
+
+// CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
+int f() {
+// Slow stack unwinding is disabled on Darwin for now, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+// CHECK-Linux-STACKTRACE: #0 {{.*}} in f(){{.*}}missing_return.cpp:[[@LINE-3]]
+// CHECK-FreeBSD-STACKTRACE: #0 {{.*}} in f(void){{.*}}missing_return.cpp:[[@LINE-4]]
+// Check for already checked line to avoid lit error reports.
+// CHECK-Darwin-STACKTRACE: missing_return.cpp
+}
+
+int main(int, char **argv) {
+ return f();
+}
diff --git a/test/ubsan/TestCases/Misc/nonnull-arg.cpp b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
new file mode 100644
index 000000000000..b1061b757899
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
@@ -0,0 +1,58 @@
+// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover %s -O3 -o %t
+// RUN: %run %t nc
+// RUN: %run %t nm
+// RUN: %run %t nf
+// RUN: %run %t nv
+// RUN: not %run %t 0c 2>&1 | FileCheck %s --check-prefix=CTOR
+// RUN: not %run %t 0m 2>&1 | FileCheck %s --check-prefix=METHOD
+// RUN: not %run %t 0f 2>&1 | FileCheck %s --check-prefix=FUNC
+// RUN: not %run %t 0v 2>&1 | FileCheck %s --check-prefix=VARIADIC
+
+class C {
+ int *null_;
+ int *nonnull_;
+
+public:
+ C(int *null, __attribute__((nonnull)) int *nonnull)
+ : null_(null), nonnull_(nonnull) {}
+ int value() { return *nonnull_; }
+ int method(int *nonnull, int *null) __attribute__((nonnull(2))) {
+ return *nonnull_ + *nonnull;
+ }
+};
+
+__attribute__((nonnull)) int func(int *nonnull) { return *nonnull; }
+
+#include <stdarg.h>
+__attribute__((nonnull)) int variadic(int x, ...) {
+ va_list args;
+ va_start(args, x);
+ int *nonnull = va_arg(args, int*);
+ int res = *nonnull;
+ va_end(args);
+ return res;
+}
+
+int main(int argc, char *argv[]) {
+ int local = 0;
+ int *arg = (argv[1][0] == '0') ? 0x0 : &local;
+ switch (argv[1][1]) {
+ case 'c':
+ return C(0x0, arg).value();
+ // CTOR: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:21: runtime error: null pointer passed as argument 2, which is declared to never be null
+ // CTOR-NEXT: {{.*}}nonnull-arg.cpp:16:31: note: nonnull attribute specified here
+ case 'm':
+ return C(0x0, &local).method(arg, 0x0);
+ // METHOD: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:36: runtime error: null pointer passed as argument 1, which is declared to never be null
+ // METHOD-NEXT: {{.*}}nonnull-arg.cpp:19:54: note: nonnull attribute specified here
+ case 'f':
+ return func(arg);
+ // FUNC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+ // FUNC-NEXT: {{.*}}nonnull-arg.cpp:24:16: note: nonnull attribute specified here
+ case 'v':
+ return variadic(42, arg);
+ // VARIADIC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:27: runtime error: null pointer passed as argument 2, which is declared to never be null
+ // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here
+ }
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Misc/nonnull.cpp b/test/ubsan/TestCases/Misc/nonnull.cpp
new file mode 100644
index 000000000000..c3ab49c11df7
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=returns-nonnull-attribute %s -O3 -o %t
+// RUN: %run %t foo
+// RUN: %run %t 2>&1 | FileCheck %s
+
+__attribute__((returns_nonnull)) char *foo(char *a);
+
+char *foo(char *a) {
+ return a;
+ // CHECK: nonnull.cpp:[[@LINE+2]]:1: runtime error: null pointer returned from function declared to never return null
+ // CHECK-NEXT: nonnull.cpp:[[@LINE-5]]:16: note: returns_nonnull attribute specified here
+}
+
+int main(int argc, char **argv) {
+ return foo(argv[1]) == 0;
+}
diff --git a/test/ubsan/TestCases/Misc/unreachable.cpp b/test/ubsan/TestCases/Misc/unreachable.cpp
new file mode 100644
index 000000000000..e1206edb30d5
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/unreachable.cpp
@@ -0,0 +1,6 @@
+// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && not %run %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/test/ubsan/TestCases/Misc/vla.c b/test/ubsan/TestCases/Misc/vla.c
new file mode 100644
index 000000000000..10721537bbbc
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/vla.c
@@ -0,0 +1,11 @@
+// RUN: %clang -fsanitize=vla-bound %s -O3 -o %t
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-MINUS-ONE
+// RUN: %run %t a 2>&1 | FileCheck %s --check-prefix=CHECK-ZERO
+// RUN: %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/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
new file mode 100644
index 000000000000..deca77d459c0
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -0,0 +1,24 @@
+// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+// Verify that we can disable symbolization if needed:
+// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
+
+// -fsanitize=function is unsupported on Darwin yet.
+// XFAIL: darwin
+
+#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:11: note: f() defined here
+ // NOSYM: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) 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/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg
new file mode 100644
index 000000000000..27c61a34387c
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg
@@ -0,0 +1,3 @@
+# 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/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
new file mode 100644
index 000000000000..79f5136db963
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -0,0 +1,105 @@
+// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t
+// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0
+// RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
+// RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
+// RUN: %run %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
+// RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
+// RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
+// RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
+// RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
+
+// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t
+// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <new>
+
+struct S {
+ S() {}
+ int f() { return 0; }
+ int k;
+};
+
+struct T : S {
+ int t;
+};
+
+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;
+ T *t = (T*)p;
+
+ void *wild = reinterpret_cast<void *>(0x123L);
+
+ (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;
+ // Slow stack unwinding is disabled on Darwin for now, see
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=137
+ // CHECK-Linux-STACK-LOAD: #0 {{.*}} in main{{.*}}misaligned.cpp
+ // Check for the already checked line to avoid lit error reports.
+ // CHECK-Darwin-STACK-LOAD: {{ }}
+
+ 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':
+ // CHECK-NEW: misaligned.cpp:[[@LINE+4]]:5: 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;
+
+ case 'u': {
+ // CHECK-UPCAST: misaligned.cpp:[[@LINE+4]]:17: runtime error: upcast of misaligned address [[PTR:0x[0-9a-f]*]] for type 'T', which requires 4 byte alignment
+ // CHECK-UPCAST-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-UPCAST-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-UPCAST-NEXT: {{^ \^}}
+ S *s2 = (S*)t;
+ return s2->f();
+ }
+
+ case 'w':
+ // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment
+ // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here
+ // CHECK-WILD-NEXT: <memory cannot be printed>
+ return static_cast<S*>(wild)->k;
+ }
+}
diff --git a/test/ubsan/TestCases/TypeCheck/null.cpp b/test/ubsan/TestCases/TypeCheck/null.cpp
new file mode 100644
index 000000000000..2a90f7fb956b
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/null.cpp
@@ -0,0 +1,38 @@
+// RUN: %clangxx -fsanitize=null %s -O3 -o %t
+// RUN: %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD
+// RUN: not --crash %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
+// RUN: %run %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
+// RUN: %run %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
+// RUN: %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/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
new file mode 100644
index 000000000000..5261e71c2d3d
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// FIXME: This test produces linker errors on Darwin.
+// XFAIL: darwin
+
+struct S { virtual int f() { return 0; } };
+struct T : virtual S {};
+
+struct Foo { virtual int f() { return 0; } };
+
+int main(int argc, char **argv) {
+ Foo foo;
+ T *t = (T*)&foo;
+ S *s = t;
+ // CHECK: vptr-virtual-base.cpp:[[@LINE-1]]:10: runtime error: cast to virtual base of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-NEXT: [[PTR]]: note: object is of type 'Foo'
+ return s->f();
+}
diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp
new file mode 100644
index 000000000000..3a6b1553f9b3
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp
@@ -0,0 +1,166 @@
+// RUN: %clangxx -fsanitize=vptr -g %s -O3 -o %t
+// RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
+// RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
+// RUN: %run %t rS && %run %t rV && %run %t oV
+// RUN: %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
+// RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
+
+// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t oU 2>&1
+
+// RUN: echo "vptr_check:S" > %t.loc-supp
+// RUN: ASAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
+
+// FIXME: This test produces linker errors on Darwin.
+// XFAIL: darwin
+// REQUIRES: stable-runtime
+
+extern "C" {
+const char *__ubsan_default_options() {
+ return "print_stacktrace=1";
+}
+}
+
+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 X {};
+struct U : S, T, virtual X { virtual int v() { return 2; } };
+
+struct V : S {};
+
+// Make p global so that lsan does not complain.
+T *p = 0;
+
+int access_p(T *p, char type);
+
+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();
+
+ 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;
+ }
+
+ access_p(p, argv[1][0]);
+ return 0;
+}
+
+int access_p(T *p, char type) {
+ switch (type) {
+ case 'r':
+ // Binding a reference to storage of appropriate size and alignment is OK.
+ {T &r = *p;}
+ break;
+
+ case 'x':
+ for (int i = 0; i < 2; i++) {
+ // Check that the first iteration ("S") succeeds, while the second ("V") fails.
+ p = reinterpret_cast<T*>((i == 0) ? new S : new V);
+ // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:7: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ vptr for 'V'}}
+ p->g();
+ }
+ return 0;
+
+ case 'm':
+ // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]: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]]
+ // CHECK-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ 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}}
+ // CHECK-NULL-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE-7]]
+
+ case 'f':
+ // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]: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]]
+ // TODO: Add check for stacktrace here.
+ return p->g();
+
+ case 'o':
+ // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]: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]]
+ // CHECK-OFFSET-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ return reinterpret_cast<U*>(p)->v() - 2;
+
+ case 'c':
+ // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]: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]]
+ // CHECK-DOWNCAST-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ static_cast<T*>(reinterpret_cast<S*>(p));
+ return 0;
+ }
+}
diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg
new file mode 100644
index 000000000000..d28733a61cf8
--- /dev/null
+++ b/test/ubsan/lit.common.cfg
@@ -0,0 +1,56 @@
+# -*- Python -*-
+
+import os
+
+def get_required_attr(config, attr_name):
+ attr_value = getattr(config, attr_name, None)
+ if attr_value == None:
+ 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.
+config.test_source_root = os.path.dirname(__file__)
+
+# Choose between standalone and UBSan+ASan modes.
+ubsan_lit_test_mode = get_required_attr(config, 'ubsan_lit_test_mode')
+if ubsan_lit_test_mode == "Standalone":
+ config.name = 'UndefinedBehaviorSanitizer-Standalone'
+ config.available_features.add("ubsan-standalone")
+ clang_ubsan_cflags = []
+elif ubsan_lit_test_mode == "AddressSanitizer":
+ if config.host_os == 'Darwin':
+ # ubsan-asan doesn't yet work on Darwin,
+ # see http://llvm.org/bugs/show_bug.cgi?id=21112.
+ config.unsupported = True
+ config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer'
+ config.available_features.add("ubsan-asan")
+ clang_ubsan_cflags = ["-fsanitize=address"]
+ config.environment['ASAN_OPTIONS'] = 'detect_leaks=0'
+else:
+ lit_config.fatal("Unknown UBSan test mode: %r" % ubsan_lit_test_mode)
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+target_cflags = [get_required_attr(config, "target_cflags")]
+clang_ubsan_cflags += target_cflags
+clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags
+
+# Define %clang and %clangxx substitutions to use in test RUN lines.
+config.substitutions.append( ("%clang ", build_invocation(clang_ubsan_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# Check that the host supports UndefinedBehaviorSanitizer tests
+if config.host_os not in ['Linux', 'Darwin', 'FreeBSD']:
+ config.unsupported = True
+
+# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL
+# because the test hangs or fails on one configuration and not the other.
+if config.target_arch.startswith('arm') == False:
+ config.available_features.add('stable-runtime')
diff --git a/test/ubsan/lit.site.cfg.in b/test/ubsan/lit.site.cfg.in
new file mode 100644
index 000000000000..ef72d2bbb42f
--- /dev/null
+++ b/test/ubsan/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Tool-specific config options.
+config.ubsan_lit_test_mode = "@UBSAN_LIT_TEST_MODE@"
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/lit.common.cfg")