1 //===-- Unittests for strtod ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/FPUtil/FPBits.h"
10 #include "src/stdlib/strtod.h"
11 
12 #include "utils/UnitTest/Test.h"
13 
14 #include <errno.h>
15 #include <limits.h>
16 #include <stddef.h>
17 
18 class LlvmLibcStrToDTest : public __llvm_libc::testing::Test {
19 public:
20   void run_test(const char *inputString, const ptrdiff_t expectedStrLen,
21                 const uint64_t expectedRawData, const int expectedErrno = 0) {
22     // expectedRawData is the expected double result as a uint64_t, organized
23     // according to IEEE754:
24     //
25     // +-- 1 Sign Bit                        +-- 52 Mantissa bits
26     // |                                     |
27     // |           +-------------------------+------------------------+
28     // |           |                                                  |
29     // SEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
30     //  |         |
31     //  +----+----+
32     //       |
33     //       +-- 11 Exponent Bits
34     //
35     //  This is so that the result can be compared in parts.
36     char *str_end = nullptr;
37 
38     __llvm_libc::fputil::FPBits<double> expected_fp =
39         __llvm_libc::fputil::FPBits<double>(expectedRawData);
40 
41     errno = 0;
42     double result = __llvm_libc::strtod(inputString, &str_end);
43 
44     __llvm_libc::fputil::FPBits<double> actual_fp =
45         __llvm_libc::fputil::FPBits<double>(result);
46 
47     EXPECT_EQ(str_end - inputString, expectedStrLen);
48 
49     EXPECT_EQ(actual_fp.bits, expected_fp.bits);
50     EXPECT_EQ(actual_fp.get_sign(), expected_fp.get_sign());
51     EXPECT_EQ(actual_fp.get_exponent(), expected_fp.get_exponent());
52     EXPECT_EQ(actual_fp.get_mantissa(), expected_fp.get_mantissa());
53     EXPECT_EQ(errno, expectedErrno);
54   }
55 };
56 
57 TEST_F(LlvmLibcStrToDTest, SimpleTest) {
58   run_test("123", 3, uint64_t(0x405ec00000000000));
59 
60   // This should fail on Eisel-Lemire, forcing a fallback to simple decimal
61   // conversion.
62   run_test("12345678901234549760", 20, uint64_t(0x43e56a95319d63d8));
63 
64   // Found while looking for difficult test cases here:
65   // https://github.com/nigeltao/parse-number-fxx-test-data/blob/main/more-test-cases/golang-org-issue-36657.txt
66   run_test("1090544144181609348835077142190", 31, uint64_t(0x462b8779f2474dfb));
67 
68   run_test("0x123", 5, uint64_t(0x4072300000000000));
69 }
70 
71 // These are tests that have caused problems in the past.
72 TEST_F(LlvmLibcStrToDTest, SpecificFailures) {
73   run_test("3E70000000000000", 16, uint64_t(0x7FF0000000000000), ERANGE);
74   run_test("358416272e-33", 13, uint64_t(0x3adbbb2a68c9d0b9));
75   run_test("2.16656806400000023841857910156251e9", 36,
76            uint64_t(0x41e0246690000001));
77   run_test("27949676547093071875", 20, uint64_t(0x43f83e132bc608c9));
78 }
79 
80 TEST_F(LlvmLibcStrToDTest, FuzzFailures) {
81   run_test("-\xff\xff\xff\xff\xff\xff\xff\x01", 0, uint64_t(0));
82   run_test("-.????", 0, uint64_t(0));
83   run_test(
84       "44444444444444444444444444444444444444444444444444A44444444444444444"
85       "44444444444*\x99\xff\xff\xff\xff",
86       50, uint64_t(0x4a3e68fdd0e0b2d8));
87   run_test("-NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNKNNNNNNNNNNNNNNNNNN?"
88            "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN?",
89            0, uint64_t(0));
90   run_test("0x.666E40", 9, uint64_t(0x3fd99b9000000000));
91 }
92