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