OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/safe_numerics.h" | |
6 | |
7 #include <stdint.h> | |
8 | |
9 #include <limits> | |
10 | |
11 #include "base/compiler_specific.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 namespace base { | |
15 namespace internal { | |
16 | |
17 // Enumerates the five different conversions types we need to test. | |
18 enum NumericConversionType { | |
19 SIGN_PRESERVING_VALUE_PRESERVING, | |
20 SIGN_PRESERVING_NARROW, | |
21 SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, | |
22 SIGN_TO_UNSIGN_NARROW, | |
23 UNSIGN_TO_SIGN_NARROW_OR_EQUAL, | |
24 }; | |
25 | |
26 // Template covering the different conversion tests. | |
27 template <typename Dst, typename Src, NumericConversionType conversion> | |
28 struct TestNumericConversion {}; | |
29 | |
30 // EXPECT_EQ wrapper providing specific detail on test failures. | |
31 #define TEST_EXPECTED_RANGE(expected, actual) \ | |
32 EXPECT_EQ(expected, RangeCheck<Dst>(actual)) << \ | |
33 "Conversion test: " << src << " value " << actual << \ | |
34 " to " << dst << " on line " << line; | |
35 | |
36 template <typename Dst, typename Src> | |
37 struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { | |
38 static void Test(const char *dst, const char *src, int line) { | |
39 typedef std::numeric_limits<Src> SrcLimits; | |
40 typedef std::numeric_limits<Dst> DstLimits; | |
41 // Integral to floating. | |
42 COMPILE_ASSERT((DstLimits::is_iec559 && SrcLimits::is_integer) || | |
43 // Not floating to integral and... | |
44 (!(DstLimits::is_integer && SrcLimits::is_iec559) && | |
45 // Same sign, same numeric, source is narrower or same. | |
46 ((SrcLimits::is_signed == DstLimits::is_signed && | |
47 sizeof(Dst) >= sizeof(Src)) || | |
48 // Or signed destination and source is smaller | |
49 (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), | |
50 comparison_must_be_sign_preserving_and_value_preserving); | |
51 | |
52 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::max()); | |
53 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(1)); | |
54 if (SrcLimits::is_iec559) { | |
55 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::max() * static_cast<Src>(-1)); | |
56 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::infinity()); | |
57 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::infinity() * -1); | |
58 TEST_EXPECTED_RANGE(TYPE_INVALID, SrcLimits::quiet_NaN()); | |
59 } else if (std::numeric_limits<Src>::is_signed) { | |
60 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(-1)); | |
61 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::min()); | |
62 } | |
63 } | |
64 }; | |
65 | |
66 template <typename Dst, typename Src> | |
67 struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { | |
68 static void Test(const char *dst, const char *src, int line) { | |
69 typedef std::numeric_limits<Src> SrcLimits; | |
70 typedef std::numeric_limits<Dst> DstLimits; | |
71 COMPILE_ASSERT(SrcLimits::is_signed == DstLimits::is_signed, | |
72 destination_and_source_sign_must_be_the_same); | |
73 COMPILE_ASSERT(sizeof(Dst) < sizeof(Src) || | |
74 (DstLimits::is_integer && SrcLimits::is_iec559), | |
75 destination_must_be_narrower_than_source); | |
76 | |
77 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::max()); | |
78 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(1)); | |
79 if (SrcLimits::is_iec559) { | |
80 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::max() * -1); | |
81 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(-1)); | |
82 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::infinity()); | |
83 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::infinity() * -1); | |
84 TEST_EXPECTED_RANGE(TYPE_INVALID, SrcLimits::quiet_NaN()); | |
85 } else if (SrcLimits::is_signed) { | |
86 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::min()); | |
87 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(-1)); | |
88 } else { | |
89 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::min()); | |
90 } | |
91 } | |
92 }; | |
93 | |
94 template <typename Dst, typename Src> | |
95 struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { | |
96 static void Test(const char *dst, const char *src, int line) { | |
97 typedef std::numeric_limits<Src> SrcLimits; | |
98 typedef std::numeric_limits<Dst> DstLimits; | |
99 COMPILE_ASSERT(sizeof(Dst) >= sizeof(Src), | |
100 destination_must_be_equal_or_wider_than_source); | |
101 COMPILE_ASSERT(SrcLimits::is_signed, source_must_be_signed); | |
102 COMPILE_ASSERT(!DstLimits::is_signed, destination_must_be_unsigned); | |
103 | |
104 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::min()); | |
105 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::max()); | |
106 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(1)); | |
107 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, static_cast<Src>(-1)); | |
108 } | |
109 }; | |
110 | |
111 template <typename Dst, typename Src> | |
112 struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { | |
113 static void Test(const char *dst, const char *src, int line) { | |
114 typedef std::numeric_limits<Src> SrcLimits; | |
115 typedef std::numeric_limits<Dst> DstLimits; | |
116 COMPILE_ASSERT((DstLimits::is_integer && SrcLimits::is_iec559) || | |
117 (sizeof(Dst) < sizeof(Src)), | |
118 destination_must_be_narrower_than_source); | |
119 COMPILE_ASSERT(SrcLimits::is_signed, source_must_be_signed); | |
120 COMPILE_ASSERT(!DstLimits::is_signed, destination_must_be_unsigned); | |
121 | |
122 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::max()); | |
123 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(1)); | |
124 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, static_cast<Src>(-1)); | |
125 if (SrcLimits::is_iec559) { | |
126 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::max() * -1); | |
127 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::infinity()); | |
128 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::infinity() * -1); | |
129 TEST_EXPECTED_RANGE(TYPE_INVALID, SrcLimits::quiet_NaN()); | |
130 } else { | |
131 TEST_EXPECTED_RANGE(TYPE_UNDERFLOW, SrcLimits::min()); | |
132 } | |
133 } | |
134 }; | |
135 | |
136 template <typename Dst, typename Src> | |
137 struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { | |
138 static void Test(const char *dst, const char *src, int line) { | |
139 typedef std::numeric_limits<Src> SrcLimits; | |
140 typedef std::numeric_limits<Dst> DstLimits; | |
141 COMPILE_ASSERT(sizeof(Dst) <= sizeof(Src), | |
142 destination_must_be_narrower_or_equal_to_source); | |
143 COMPILE_ASSERT(!SrcLimits::is_signed, source_must_be_unsigned); | |
144 COMPILE_ASSERT(DstLimits::is_signed, destination_must_be_signed); | |
145 | |
146 TEST_EXPECTED_RANGE(TYPE_VALID, SrcLimits::min()); | |
147 TEST_EXPECTED_RANGE(TYPE_OVERFLOW, SrcLimits::max()); | |
148 TEST_EXPECTED_RANGE(TYPE_VALID, static_cast<Src>(1)); | |
149 } | |
150 }; | |
151 | |
152 // Helper macro to wrap displaying the conversion types and line numbers | |
153 #define TEST_NUMERIC_CONVERSION(d, s, t) \ | |
154 TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__) | |
155 | |
156 TEST(SafeNumerics, IntMinConversions) { | |
157 TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
158 TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
159 | |
160 TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); | |
161 TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); | |
162 TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); | |
163 | |
164 TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
165 | |
166 TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); | |
167 TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); | |
168 TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); | |
169 | |
170 TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
171 TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
172 } | |
173 | |
174 TEST(SafeNumerics, IntConversions) { | |
175 TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); | |
176 TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, | |
177 SIGN_PRESERVING_VALUE_PRESERVING); | |
178 TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
179 TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, | |
180 SIGN_PRESERVING_VALUE_PRESERVING); | |
181 TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
182 | |
183 TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); | |
184 TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); | |
185 TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); | |
186 TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); | |
187 | |
188 TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
189 TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
190 | |
191 TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); | |
192 TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); | |
193 TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); | |
194 | |
195 TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
196 TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
197 } | |
198 | |
199 TEST(SafeNumerics, IntMaxConversions) { | |
200 TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
201 TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, | |
202 SIGN_PRESERVING_VALUE_PRESERVING); | |
203 TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); | |
204 TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, | |
205 SIGN_PRESERVING_VALUE_PRESERVING); | |
206 TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, | |
207 SIGN_PRESERVING_VALUE_PRESERVING); | |
208 TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
209 | |
210 TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); | |
211 TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); | |
212 | |
213 TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
214 TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
215 | |
216 TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); | |
217 TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); | |
218 | |
219 TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
220 } | |
221 | |
222 TEST(SafeNumerics, FloatConversions) { | |
223 TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
224 TEST_NUMERIC_CONVERSION(float, uintmax_t, | |
225 SIGN_PRESERVING_VALUE_PRESERVING); | |
226 TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); | |
227 TEST_NUMERIC_CONVERSION(float, unsigned int, | |
228 SIGN_PRESERVING_VALUE_PRESERVING); | |
229 | |
230 TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); | |
231 } | |
232 | |
233 TEST(SafeNumerics, DoubleConversions) { | |
234 TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); | |
235 TEST_NUMERIC_CONVERSION(double, uintmax_t, | |
236 SIGN_PRESERVING_VALUE_PRESERVING); | |
237 TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); | |
238 TEST_NUMERIC_CONVERSION(double, unsigned int, | |
239 SIGN_PRESERVING_VALUE_PRESERVING); | |
240 } | |
241 | |
242 TEST(SafeNumerics, SizeTConversions) { | |
243 TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); | |
244 TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); | |
245 } | |
246 | |
247 TEST(SafeNumerics, CastTests) { | |
248 // MSVC catches and warns that we're forcing saturation in these tests. | |
249 // Since that's intentional, we need to shut this warning off. | |
250 #if defined(COMPILER_MSVC) | |
251 #pragma warning(disable : 4756) | |
252 #endif | |
253 | |
254 int small_positive = 1; | |
255 int small_negative = -1; | |
256 double double_small = 1.0; | |
257 double double_large = std::numeric_limits<double>::max(); | |
258 double double_infinity = std::numeric_limits<float>::infinity(); | |
259 | |
260 // Just test that the cast compiles, since the other tests cover logic. | |
261 EXPECT_EQ(0, base::checked_numeric_cast<int>(static_cast<size_t>(0))); | |
262 | |
263 // Test various saturation corner cases. | |
264 EXPECT_EQ(saturated_cast<int>(small_negative), | |
265 static_cast<int>(small_negative)); | |
266 EXPECT_EQ(saturated_cast<int>(small_positive), | |
267 static_cast<int>(small_positive)); | |
268 EXPECT_EQ(saturated_cast<unsigned>(small_negative), | |
269 static_cast<unsigned>(0)); | |
270 EXPECT_EQ(saturated_cast<int>(double_small), | |
271 static_cast<int>(double_small)); | |
272 EXPECT_EQ(saturated_cast<int>(double_large), | |
273 std::numeric_limits<int>::max()); | |
274 EXPECT_EQ(saturated_cast<float>(double_large), double_infinity); | |
275 EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity); | |
276 } | |
277 | |
278 } // namespace internal | |
279 } // namespace base | |
OLD | NEW |