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 | |