| 1 | // RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t |
| 2 | // RUN: %run %t _ |
| 3 | // RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0 |
| 4 | // RUN: %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1 |
| 5 | // RUN: %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2 |
| 6 | // RUN: %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3 |
| 7 | // RUN: %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4 |
| 8 | // RUN: %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5 |
| 9 | // RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6 |
| 10 | // RUN: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7 |
| 11 | |
| 12 | // Issue #41838 |
| 13 | // XFAIL: sparc-target-arch && target={{.*solaris.*}} |
| 14 | |
| 15 | // This test assumes float and double are IEEE-754 single- and double-precision. |
| 16 | |
| 17 | #if defined(__APPLE__) |
| 18 | # include <machine/endian.h> |
| 19 | # define BYTE_ORDER __DARWIN_BYTE_ORDER |
| 20 | # define BIG_ENDIAN __DARWIN_BIG_ENDIAN |
| 21 | # define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN |
| 22 | #elif defined(__FreeBSD__) || defined(__NetBSD__) |
| 23 | # include <sys/endian.h> |
| 24 | # ifndef BYTE_ORDER |
| 25 | # define BYTE_ORDER _BYTE_ORDER |
| 26 | # endif |
| 27 | # ifndef BIG_ENDIAN |
| 28 | # define BIG_ENDIAN _BIG_ENDIAN |
| 29 | # endif |
| 30 | # ifndef LITTLE_ENDIAN |
| 31 | # define LITTLE_ENDIAN _LITTLE_ENDIAN |
| 32 | # endif |
| 33 | #elif defined(__sun__) && defined(__svr4__) |
| 34 | // Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h. |
| 35 | # include <sys/types.h> |
| 36 | # define BIG_ENDIAN 4321 |
| 37 | # define LITTLE_ENDIAN 1234 |
| 38 | # if defined(_BIG_ENDIAN) |
| 39 | # define BYTE_ORDER BIG_ENDIAN |
| 40 | # else |
| 41 | # define BYTE_ORDER LITTLE_ENDIAN |
| 42 | # endif |
| 43 | #elif defined(_WIN32) |
| 44 | # define BYTE_ORDER 0 |
| 45 | # define BIG_ENDIAN 1 |
| 46 | # define LITTLE_ENDIAN 0 |
| 47 | #else |
| 48 | # include <endian.h> |
| 49 | # define BYTE_ORDER __BYTE_ORDER |
| 50 | # define BIG_ENDIAN __BIG_ENDIAN |
| 51 | # define LITTLE_ENDIAN __LITTLE_ENDIAN |
| 52 | #endif // __APPLE__ |
| 53 | #include <stdint.h> |
| 54 | #include <stdio.h> |
| 55 | #include <string.h> |
| 56 | |
| 57 | float Inf; |
| 58 | float NaN; |
| 59 | |
| 60 | int main(int argc, char **argv) { |
| 61 | float MaxFloatRepresentableAsInt = 0x7fffff80; |
| 62 | (int)MaxFloatRepresentableAsInt; // ok |
| 63 | (int)-MaxFloatRepresentableAsInt; // ok |
| 64 | |
| 65 | float MinFloatRepresentableAsInt = -0x7fffffff - 1; |
| 66 | (int)MinFloatRepresentableAsInt; // ok |
| 67 | |
| 68 | float MaxFloatRepresentableAsUInt = 0xffffff00u; |
| 69 | (unsigned int)MaxFloatRepresentableAsUInt; // ok |
| 70 | |
| 71 | #ifdef __SIZEOF_INT128__ |
| 72 | unsigned __int128 FloatMaxAsUInt128 = -((unsigned __int128)1 << 104); |
| 73 | (void)(float)FloatMaxAsUInt128; // ok |
| 74 | #endif |
| 75 | |
| 76 | float NearlyMinusOne = -0.99999; |
| 77 | unsigned Zero = NearlyMinusOne; // ok |
| 78 | |
| 79 | // Build a '+Inf'. |
| 80 | #if BYTE_ORDER == LITTLE_ENDIAN |
| 81 | unsigned char InfVal[] = {0x00, 0x00, 0x80, 0x7f}; |
| 82 | #else |
| 83 | unsigned char InfVal[] = {0x7f, 0x80, 0x00, 0x00}; |
| 84 | #endif |
| 85 | float Inf; |
| 86 | memcpy(dest: &Inf, src: InfVal, n: 4); |
| 87 | |
| 88 | // Build a 'NaN'. |
| 89 | #if BYTE_ORDER == LITTLE_ENDIAN |
| 90 | unsigned char NaNVal[] = {0x01, 0x00, 0x80, 0x7f}; |
| 91 | #else |
| 92 | unsigned char NaNVal[] = {0x7f, 0x80, 0x00, 0x01}; |
| 93 | #endif |
| 94 | float NaN; |
| 95 | memcpy(dest: &NaN, src: NaNVal, n: 4); |
| 96 | |
| 97 | double DblInf = (double)Inf; // ok |
| 98 | |
| 99 | switch (argv[1][0]) { |
| 100 | // FIXME: Produce a source location for these checks and test for it here. |
| 101 | |
| 102 | // Floating point -> integer overflow. |
| 103 | case '0': { |
| 104 | // Note that values between 0x7ffffe00 and 0x80000000 may or may not |
| 105 | // successfully round-trip, depending on the rounding mode. |
| 106 | // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: 2.14748{{.*}} is outside the range of representable values of type 'int' |
| 107 | static int test_int = MaxFloatRepresentableAsInt + 0x80; |
| 108 | // CHECK-0: SUMMARY: {{.*}}Sanitizer: float-cast-overflow {{.*}}cast-overflow.cpp:[[@LINE-1]] |
| 109 | return 0; |
| 110 | } |
| 111 | case '1': { |
| 112 | // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: -2.14748{{.*}} is outside the range of representable values of type 'int' |
| 113 | static int test_int = MinFloatRepresentableAsInt - 0x100; |
| 114 | return 0; |
| 115 | } |
| 116 | case '2': { |
| 117 | // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: -1 is outside the range of representable values of type 'unsigned int' |
| 118 | volatile float f = -1.0; |
| 119 | volatile unsigned u = (unsigned)f; |
| 120 | return 0; |
| 121 | } |
| 122 | case '3': { |
| 123 | // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: 4.2949{{.*}} is outside the range of representable values of type 'unsigned int' |
| 124 | static int test_int = (unsigned)(MaxFloatRepresentableAsUInt + 0x100); |
| 125 | return 0; |
| 126 | } |
| 127 | |
| 128 | case '4': { |
| 129 | // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int' |
| 130 | static int test_int = Inf; |
| 131 | return 0; |
| 132 | } |
| 133 | case '5': { |
| 134 | // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int' |
| 135 | static int test_int = NaN; |
| 136 | return 0; |
| 137 | } |
| 138 | // Integer -> floating point overflow. |
| 139 | case '6': { |
| 140 | // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{27: runtime error: 3.40282e\+38 is outside the range of representable values of type 'int'| __int128 not supported}} |
| 141 | #if defined(__SIZEOF_INT128__) && !defined(_WIN32) |
| 142 | static int test_int = (float)(FloatMaxAsUInt128 + 1); |
| 143 | return 0; |
| 144 | #else |
| 145 | // Print the same line as the check above. |
| 146 | // That way the test is robust to line changes around it |
| 147 | printf("%s:%d: __int128 not supported" , __FILE__, __LINE__ - 5); |
| 148 | return 0; |
| 149 | #endif |
| 150 | } |
| 151 | case '7': { |
| 152 | volatile long double ld = 300.0; |
| 153 | // CHECK-7: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: 300 is outside the range of representable values of type 'char' |
| 154 | char c = ld; |
| 155 | // `c` is allowed to contain UNDEF, thus we should not use |
| 156 | // its value as an exit code. |
| 157 | return 0; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | |