1 // Copyright 2015 The PDFium Authors
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 <math.h>
6
7 #include <iterator>
8 #include <limits>
9
10 #include "build/build_config.h"
11 #include "core/fxcrt/compiler_specific.h"
12 #include "core/fxcrt/fx_string.h"
13 #include "core/fxcrt/fx_system.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 // Unit test covering cases where PDFium replaces well-known library
17 // functionality on any given platformn.
18
19 #if !BUILDFLAG(IS_WIN)
20
21 namespace {
22
23 const char kSentinel = 0x7f;
24
Check32BitBase16Itoa(int32_t input,const char * expected_output)25 void Check32BitBase16Itoa(int32_t input, const char* expected_output) {
26 const size_t kBufLen = 11; // "-" + 8 digits + NUL + sentinel.
27 char buf[kBufLen];
28 UNSAFE_TODO({
29 buf[kBufLen - 1] = kSentinel;
30 FXSYS_itoa(input, buf, 16);
31 EXPECT_STREQ(expected_output, buf);
32 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
33 });
34 }
35
Check32BitBase10Itoa(int32_t input,const char * expected_output)36 void Check32BitBase10Itoa(int32_t input, const char* expected_output) {
37 const size_t kBufLen = 13; // "-" + 10 digits + NUL + sentinel.
38 char buf[kBufLen];
39 UNSAFE_TODO({
40 buf[kBufLen - 1] = kSentinel;
41 FXSYS_itoa(input, buf, 10);
42 EXPECT_STREQ(expected_output, buf);
43 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
44 });
45 }
46
Check32BitBase2Itoa(int32_t input,const char * expected_output)47 void Check32BitBase2Itoa(int32_t input, const char* expected_output) {
48 const size_t kBufLen = 35; // "-" + 32 digits + NUL + sentinel.
49 char buf[kBufLen];
50 UNSAFE_TODO({
51 buf[kBufLen - 1] = kSentinel;
52 FXSYS_itoa(input, buf, 2);
53 EXPECT_STREQ(expected_output, buf);
54 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
55 });
56 }
57
Check64BitBase16Itoa(int64_t input,const char * expected_output)58 void Check64BitBase16Itoa(int64_t input, const char* expected_output) {
59 const size_t kBufLen = 19; // "-" + 16 digits + NUL + sentinel.
60 char buf[kBufLen];
61 UNSAFE_TODO({
62 buf[kBufLen - 1] = kSentinel;
63 FXSYS_i64toa(input, buf, 16);
64 EXPECT_STREQ(expected_output, buf);
65 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
66 });
67 }
68
Check64BitBase10Itoa(int64_t input,const char * expected_output)69 void Check64BitBase10Itoa(int64_t input, const char* expected_output) {
70 const size_t kBufLen = 22; // "-" + 19 digits + NUL + sentinel.
71 char buf[kBufLen];
72 UNSAFE_TODO({
73 buf[kBufLen - 1] = kSentinel;
74 FXSYS_i64toa(input, buf, 10);
75 EXPECT_STREQ(expected_output, buf);
76 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
77 });
78 }
79
Check64BitBase2Itoa(int64_t input,const char * expected_output)80 void Check64BitBase2Itoa(int64_t input, const char* expected_output) {
81 const size_t kBufLen = 67; // "-" + 64 digits + NUL + sentinel.
82 char buf[kBufLen];
83 UNSAFE_TODO({
84 buf[kBufLen - 1] = kSentinel;
85 FXSYS_i64toa(input, buf, 2);
86 EXPECT_STREQ(expected_output, buf);
87 EXPECT_EQ(kSentinel, buf[kBufLen - 1]);
88 });
89 }
90
91 } // namespace
92
TEST(fxcrt,FXSYSroundf)93 TEST(fxcrt, FXSYSroundf) {
94 EXPECT_EQ(0, FXSYS_roundf(0.0f));
95 EXPECT_EQ(0, FXSYS_roundf(-0.0f));
96 EXPECT_EQ(0, FXSYS_roundf(0.00001f));
97 EXPECT_EQ(0, FXSYS_roundf(-0.00001f));
98 EXPECT_EQ(3, FXSYS_roundf(3.14159f));
99 EXPECT_EQ(4, FXSYS_roundf(3.5f));
100
101 // Check for smallest non-zero float values.
102 EXPECT_EQ(0, FXSYS_roundf(std::numeric_limits<float>::min()));
103 EXPECT_EQ(0, FXSYS_roundf(-std::numeric_limits<float>::min()));
104
105 // Function is a wrapper around standard C library function round(), so
106 // returns the integral value that is nearest to x, with halfway cases
107 // rounded away from zero.
108 EXPECT_EQ(-3, FXSYS_roundf(-3.14159f));
109 EXPECT_EQ(-4, FXSYS_roundf(-3.5f));
110
111 // Positive rounding stops at maximum int.
112 // MAX_INT=0x7FFFFFFF=2147483647=2.147483647e+9
113 // In IEEE-754 format, 2^31 yields exponent of 0x9E with mantissa of all
114 // zeroes which is 0x4f000000=2.14748365e+9, which is beyond max integer.
115 // Going to next smallest float by minus one from exponent and mantissa of
116 // all ones yields binary float representation of 0x4EFFFFFF=2.14748352e+9,
117 // which is 2147483520.
118 EXPECT_EQ(2147483520, FXSYS_roundf(2.14748352e+9f));
119
120 // Using a slightly larger value, expect to see it be capped at MAX_INT.
121 EXPECT_EQ(2147483647, FXSYS_roundf(2.14748365e+9f));
122
123 EXPECT_EQ(2147483647, FXSYS_roundf(2.14748365e+10f));
124 EXPECT_EQ(2147483647, FXSYS_roundf(std::numeric_limits<float>::max()));
125
126 // Negative rounding stops at minimum int.
127 // MIN_INT=0x80000000=-2147483648,=-2.147483648e+9
128 // In IEEE-754 format, 2^31 yields exponent of 0x9E with mantissa of all
129 // zeroes which is 0x4f000000=2.14748365e+9, and the sign bit set, which
130 // is 0xCF000000 and exactly matches the minimum integer. Going to next
131 // smallest negative float by minus one from exponent and mantissa of all
132 // ones yields binary float representation of 0xCEFFFFFF=-2.14748352e+9,
133 // which is -2147483520.
134 EXPECT_EQ(-2147483648, FXSYS_roundf(-2.147483648e+10f));
135 EXPECT_EQ(-2147483648, FXSYS_roundf(-2.147483648e+9f));
136 EXPECT_EQ(-2147483520, FXSYS_roundf(-2.14748352e+9f));
137 EXPECT_EQ(-2147483648, FXSYS_roundf(-std::numeric_limits<float>::max()));
138
139 // NaN should give zero.
140 EXPECT_EQ(0, FXSYS_roundf(NAN));
141 }
142
TEST(fxcrt,FXSYSround)143 TEST(fxcrt, FXSYSround) {
144 EXPECT_EQ(0, FXSYS_round(0.0));
145 EXPECT_EQ(0, FXSYS_round(-0.0));
146 EXPECT_EQ(0, FXSYS_round(0.00001));
147 EXPECT_EQ(0, FXSYS_round(-0.00001));
148 EXPECT_EQ(3, FXSYS_round(3.14159));
149 EXPECT_EQ(4, FXSYS_round(3.5));
150
151 // Check for smallest non-zero double values.
152 EXPECT_EQ(0, FXSYS_round(std::numeric_limits<double>::min()));
153 EXPECT_EQ(0, FXSYS_round(-std::numeric_limits<double>::min()));
154
155 // Function is a wrapper around standard C library function round(), so
156 // returns the integral value that is nearest to x, with halfway cases
157 // rounded away from zero.
158 EXPECT_EQ(-3, FXSYS_round(-3.14159));
159 EXPECT_EQ(-4, FXSYS_round(-3.5));
160
161 // Positive rounding stops at maximum int.
162 // MAX_INT=0x7FFFFFFF=2147483647=2.147483647e+9
163 // In IEEE-754 double precision format, 2^31 yields exponent of 0x41E with
164 // mantissa of all zeroes which is 0x41E0000000000000=2.14748365e+9, which
165 // is beyond max integer.
166 // Going to next smallest float by minus one from exponent and mantissa of
167 // all ones yields binary float representation of
168 // 41DFFFFFFFC00000=2.147483647e+9, which matches the max integer.
169 EXPECT_EQ(2147483647, FXSYS_round(2.147483647e+9));
170
171 // Using a slightly larger value, expect to see it be capped at MAX_INT.
172 EXPECT_EQ(2147483647, FXSYS_round(2.14748365e+9));
173
174 EXPECT_EQ(2147483647, FXSYS_round(2.14748365e+10));
175 EXPECT_EQ(2147483647, FXSYS_round(std::numeric_limits<double>::max()));
176
177 // Negative rounding stops at minimum int.
178 // MIN_INT=0x80000000=-2147483648,=-2.147483648e+9
179 // In IEEE-754 double precision format, 2^31 yields exponent of 0x41E with
180 // mantissa of all zeroes which is 0x41E0000000000000=2.14748365e+9, and the
181 // sign bit set, which is 0xC1E0000000000000 and exactly matches the minimum
182 // integer. Going to next smallest negative double by minus one from
183 // exponent and mantissa of all ones yields binary float representation of
184 // 0xC1DFFFFFFFFFFFFF=-2.1474836479999998e+9, which is -2147483648.
185 EXPECT_EQ(-2147483648, FXSYS_round(-2.1474836479999998e+9));
186 EXPECT_EQ(-2147483648, FXSYS_round(-2.147483648e+9));
187 EXPECT_EQ(-2147483648, FXSYS_round(-2.147483648e+10));
188 EXPECT_EQ(-2147483648, FXSYS_round(-std::numeric_limits<double>::max()));
189
190 // NaN should give zero.
191 EXPECT_EQ(0, FXSYS_round(NAN));
192 }
193
TEST(fxcrt,FXSYSitoaInvalidRadix)194 TEST(fxcrt, FXSYSitoaInvalidRadix) {
195 char buf[32];
196
197 FXSYS_itoa(42, buf, 17); // Ours stops at 16.
198 EXPECT_STREQ("", buf);
199
200 FXSYS_itoa(42, buf, 1);
201 EXPECT_STREQ("", buf);
202
203 FXSYS_itoa(42, buf, 0);
204 EXPECT_STREQ("", buf);
205
206 FXSYS_itoa(42, buf, -1);
207 EXPECT_STREQ("", buf);
208 }
209
TEST(fxcrt,FXSYSitoa)210 TEST(fxcrt, FXSYSitoa) {
211 Check32BitBase16Itoa(std::numeric_limits<int32_t>::min(), "-80000000");
212 Check32BitBase10Itoa(std::numeric_limits<int32_t>::min(), "-2147483648");
213 Check32BitBase2Itoa(std::numeric_limits<int32_t>::min(),
214 "-10000000000000000000000000000000");
215
216 Check32BitBase16Itoa(-1, "-1");
217 Check32BitBase10Itoa(-1, "-1");
218 Check32BitBase2Itoa(-1, "-1");
219
220 Check32BitBase16Itoa(0, "0");
221 Check32BitBase10Itoa(0, "0");
222 Check32BitBase2Itoa(0, "0");
223
224 Check32BitBase16Itoa(42, "2a");
225 Check32BitBase10Itoa(42, "42");
226 Check32BitBase2Itoa(42, "101010");
227
228 Check32BitBase16Itoa(std::numeric_limits<int32_t>::max(), "7fffffff");
229 Check32BitBase10Itoa(std::numeric_limits<int32_t>::max(), "2147483647");
230 Check32BitBase2Itoa(std::numeric_limits<int32_t>::max(),
231 "1111111111111111111111111111111");
232 }
233
TEST(fxcrt,FXSYSi64toaInvalidRadix)234 TEST(fxcrt, FXSYSi64toaInvalidRadix) {
235 char buf[32];
236
237 FXSYS_i64toa(42, buf, 17); // Ours stops at 16.
238 EXPECT_STREQ("", buf);
239
240 FXSYS_i64toa(42, buf, 1);
241 EXPECT_STREQ("", buf);
242
243 FXSYS_i64toa(42, buf, 0);
244 EXPECT_STREQ("", buf);
245
246 FXSYS_i64toa(42, buf, -1);
247 EXPECT_STREQ("", buf);
248 }
249
TEST(fxcrt,FXSYSi64toa)250 TEST(fxcrt, FXSYSi64toa) {
251 Check64BitBase16Itoa(std::numeric_limits<int64_t>::min(),
252 "-8000000000000000");
253 Check64BitBase10Itoa(std::numeric_limits<int64_t>::min(),
254 "-9223372036854775808");
255 Check64BitBase2Itoa(
256 std::numeric_limits<int64_t>::min(),
257 "-1000000000000000000000000000000000000000000000000000000000000000");
258
259 Check64BitBase16Itoa(-1, "-1");
260 Check64BitBase10Itoa(-1, "-1");
261 Check64BitBase2Itoa(-1, "-1");
262
263 Check64BitBase16Itoa(0, "0");
264 Check64BitBase10Itoa(0, "0");
265 Check64BitBase2Itoa(0, "0");
266
267 Check64BitBase16Itoa(42, "2a");
268 Check64BitBase10Itoa(42, "42");
269 Check64BitBase2Itoa(42, "101010");
270
271 Check64BitBase16Itoa(std::numeric_limits<int64_t>::max(), "7fffffffffffffff");
272 Check64BitBase10Itoa(std::numeric_limits<int64_t>::max(),
273 "9223372036854775807");
274 Check64BitBase2Itoa(
275 std::numeric_limits<int64_t>::max(),
276 "111111111111111111111111111111111111111111111111111111111111111");
277 }
278
279 #endif // !BUILDFLAG(IS_WIN)
280
TEST(fxcrt,FXSYSwcsftime)281 TEST(fxcrt, FXSYSwcsftime) {
282 struct tm good_time = {};
283 good_time.tm_year = 74; // 1900-based.
284 good_time.tm_mon = 7; // 0-based.
285 good_time.tm_mday = 9; // 1-based.
286 good_time.tm_hour = 11;
287 good_time.tm_min = 59;
288 good_time.tm_sec = 59;
289
290 wchar_t buf[100] = {};
291 EXPECT_EQ(19u, UNSAFE_TODO(FXSYS_wcsftime(buf, std::size(buf),
292 L"%Y-%m-%dT%H:%M:%S", &good_time)));
293 EXPECT_STREQ(L"1974-08-09T11:59:59", buf);
294
295 // Ensure wcsftime handles a wide range of years without crashing.
296 struct tm year_time = {};
297 year_time.tm_mon = 7; // 0-based.
298 year_time.tm_mday = 9; // 1-based.
299 year_time.tm_hour = 11;
300 year_time.tm_min = 59;
301 year_time.tm_sec = 59;
302
303 for (int year = -2500; year <= 8500; ++year) {
304 year_time.tm_year = year;
305 wchar_t year_buf[100] = {};
306 UNSAFE_TODO(FXSYS_wcsftime(year_buf, std::size(year_buf),
307 L"%Y-%m-%dT%H:%M:%S", &year_time));
308 }
309
310 // Ensure wcsftime handles bad years, etc. without crashing.
311 struct tm bad_time = {};
312 bad_time.tm_year = -1;
313 bad_time.tm_mon = -1;
314 bad_time.tm_mday = -1;
315 bad_time.tm_hour = -1;
316 bad_time.tm_min = -1;
317 bad_time.tm_sec = -1;
318
319 UNSAFE_TODO(
320 FXSYS_wcsftime(buf, std::size(buf), L"%y-%m-%dT%H:%M:%S", &bad_time));
321
322 // Ensure wcsftime handles bad-ish day without crashing (Feb 30).
323 struct tm feb_time = {};
324 feb_time.tm_year = 115; // 1900-based.
325 feb_time.tm_mon = 1; // 0-based.
326 feb_time.tm_mday = 30; // 1-based.
327 feb_time.tm_hour = 12;
328 feb_time.tm_min = 00;
329 feb_time.tm_sec = 00;
330
331 UNSAFE_TODO(
332 FXSYS_wcsftime(buf, std::size(buf), L"%y-%m-%dT%H:%M:%S", &feb_time));
333 }
334
TEST(fxcrt,FXSYSatoi)335 TEST(fxcrt, FXSYSatoi) {
336 EXPECT_EQ(0, FXSYS_atoi(""));
337 EXPECT_EQ(0, FXSYS_atoi("0"));
338 EXPECT_EQ(-1, FXSYS_atoi("-1"));
339 EXPECT_EQ(2345, FXSYS_atoi("2345"));
340 EXPECT_EQ(-2147483647, FXSYS_atoi("-2147483647"));
341 // Handle the sign.
342 EXPECT_EQ(-2345, FXSYS_atoi("-2345"));
343 EXPECT_EQ(2345, FXSYS_atoi("+2345"));
344 // The max value.
345 EXPECT_EQ(2147483647, FXSYS_atoi("2147483647"));
346 // The min value. Written in -1 format to avoid "unary minus operator applied
347 // to unsigned type" warning.
348 EXPECT_EQ(-2147483647 - 1, FXSYS_atoi("-2147483648"));
349 // With invalid char.
350 EXPECT_EQ(9, FXSYS_atoi("9x9"));
351
352 // Out of range values.
353 EXPECT_EQ(2147483647, FXSYS_atoi("2147483623423412348"));
354 EXPECT_EQ(2147483647, FXSYS_atoi("2147483648"));
355 EXPECT_EQ(-2147483647 - 1, FXSYS_atoi("-2147483650"));
356 }
357
TEST(fxcrt,FXSYSatoi64)358 TEST(fxcrt, FXSYSatoi64) {
359 EXPECT_EQ(0, FXSYS_atoi64(""));
360 EXPECT_EQ(0, FXSYS_atoi64("0"));
361 EXPECT_EQ(-1, FXSYS_atoi64("-1"));
362 EXPECT_EQ(2345, FXSYS_atoi64("2345"));
363 EXPECT_EQ(-9223372036854775807LL, FXSYS_atoi64("-9223372036854775807"));
364 // Handle the sign.
365 EXPECT_EQ(-2345, FXSYS_atoi64("-2345"));
366 EXPECT_EQ(2345, FXSYS_atoi64("+2345"));
367 // The max value.
368 EXPECT_EQ(9223372036854775807LL, FXSYS_atoi64("9223372036854775807"));
369 // The min value. Written in -1 format to avoid implicit unsigned warning.
370 EXPECT_EQ(-9223372036854775807LL - 1LL, FXSYS_atoi64("-9223372036854775808"));
371 // With invalid char.
372 EXPECT_EQ(9, FXSYS_atoi64("9x9"));
373
374 // Out of range values.
375 EXPECT_EQ(9223372036854775807LL, FXSYS_atoi64("922337203685471234123475807"));
376 EXPECT_EQ(9223372036854775807LL, FXSYS_atoi64("9223372036854775808"));
377 EXPECT_EQ(-9223372036854775807LL - 1LL, FXSYS_atoi64("-9223372036854775810"));
378 }
379
TEST(fxcrt,FXSYSwtoi)380 TEST(fxcrt, FXSYSwtoi) {
381 EXPECT_EQ(0, FXSYS_wtoi(L""));
382 EXPECT_EQ(0, FXSYS_wtoi(L"0"));
383 EXPECT_EQ(-1, FXSYS_wtoi(L"-1"));
384 EXPECT_EQ(2345, FXSYS_wtoi(L"2345"));
385 EXPECT_EQ(-2147483647, FXSYS_wtoi(L"-2147483647"));
386 // The max value.
387 EXPECT_EQ(2147483647, FXSYS_wtoi(L"2147483647"));
388 // The min value.
389 EXPECT_EQ(-2147483647 - 1, FXSYS_wtoi(L"-2147483648"));
390
391 // Out of range values.
392 EXPECT_EQ(2147483647, FXSYS_wtoi(L"2147483623423412348"));
393 EXPECT_EQ(2147483647, FXSYS_wtoi(L"2147483648"));
394 EXPECT_EQ(-2147483647 - 1, FXSYS_wtoi(L"-2147483652"));
395 }
396
TEST(fxcrt,FXSYSatoui)397 TEST(fxcrt, FXSYSatoui) {
398 EXPECT_EQ(0u, FXSYS_atoui(""));
399 EXPECT_EQ(0u, FXSYS_atoui("0"));
400 EXPECT_EQ(4294967295, FXSYS_atoui("-1"));
401 EXPECT_EQ(2345u, FXSYS_atoui("2345"));
402 // Handle the sign.
403 EXPECT_EQ(4294964951, FXSYS_atoui("-2345"));
404 EXPECT_EQ(2345u, FXSYS_atoui("+2345"));
405 // The max value.
406 EXPECT_EQ(4294967295, FXSYS_atoui("4294967295"));
407 EXPECT_EQ(9u, FXSYS_atoui("9x9"));
408
409 // Out of range values.
410 EXPECT_EQ(4294967295, FXSYS_atoui("2147483623423412348"));
411 EXPECT_EQ(4294967295, FXSYS_atoui("4294967296"));
412 EXPECT_EQ(4294967295, FXSYS_atoui("-4294967345"));
413 }
414