1 //===-- strtofloat_fuzz.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 /// Fuzzing test for llvm-libc atof implementation.
11 //===----------------------------------------------------------------------===//
12 #include "src/stdlib/atof.h"
13 #include "src/stdlib/strtod.h"
14 #include "src/stdlib/strtof.h"
15 #include "src/stdlib/strtold.h"
17 #include "src/__support/FPUtil/FloatProperties.h"
23 #include "utils/MPFRWrapper/mpfr_inc.h"
25 using LIBC_NAMESPACE::fputil::FloatProperties
;
27 // This function calculates the effective precision for a given float type and
28 // exponent. Subnormals have a lower effective precision since they don't
29 // necessarily use all of the bits of the mantissa.
30 template <typename F
> inline constexpr int effective_precision(int exponent
) {
31 const int full_precision
= FloatProperties
<F
>::MANTISSA_PRECISION
;
33 // This is intended to be 0 when the exponent is the lowest normal and
34 // increase as the exponent's magnitude increases.
35 const int bits_below_normal
=
36 (-exponent
) - (FloatProperties
<F
>::EXPONENT_BIAS
- 1);
38 // The precision should be the normal, full precision, minus the bits lost
39 // by this being a subnormal, minus one for the implicit leading one.
40 const int bits_if_subnormal
= full_precision
- bits_below_normal
- 1;
42 if (bits_below_normal
>= 0) {
43 return bits_if_subnormal
;
45 return full_precision
;
48 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data
, size_t size
) {
49 // const char newstr[] = "123";
50 // data = reinterpret_cast<const uint8_t *>(newstr);
51 // size = sizeof(newstr);
52 uint8_t *container
= new uint8_t[size
+ 1];
57 for (i
= 0; i
< size
; ++i
) {
58 // MPFR's strtofr uses "@" as a base-independent exponent symbol
60 container
[i
] = data
[i
];
65 container
[size
] = '\0'; // Add null terminator to container.
67 const char *str_ptr
= reinterpret_cast<const char *>(container
);
69 char *out_ptr
= nullptr;
73 // This is just used to determine the base and precision.
75 mpfr_init2(result
, 256);
77 mpfr_init2(bin_result
, 256);
78 mpfr_strtofr(result
, str_ptr
, &out_ptr
, 0 /* base */, MPFR_RNDN
);
79 ptrdiff_t result_strlen
= out_ptr
- str_ptr
;
80 mpfr_strtofr(bin_result
, str_ptr
, &out_ptr
, 2 /* base */, MPFR_RNDN
);
81 ptrdiff_t bin_result_strlen
= out_ptr
- str_ptr
;
83 long double bin_result_ld
= mpfr_get_ld(bin_result
, MPFR_RNDN
);
84 long double result_ld
= mpfr_get_ld(result
, MPFR_RNDN
);
86 // This detects if mpfr's strtofr selected a base of 2, which libc does not
87 // support. If a base 2 decoding is detected, it is replaced by a base 10
89 if ((bin_result_ld
!= 0.0 || bin_result_strlen
== result_strlen
) &&
90 bin_result_ld
== result_ld
) {
91 mpfr_strtofr(result
, str_ptr
, &out_ptr
, 10 /* base */, MPFR_RNDN
);
92 result_strlen
= out_ptr
- str_ptr
;
96 auto result_exp
= mpfr_get_exp(result
);
99 mpfr_clear(bin_result
);
101 // These must be calculated with the correct precision, and not any more, to
102 // prevent numbers like 66336650.00...01 (many zeroes) from causing an issue.
103 // 66336650 is exactly between two float values (66336652 and 66336648) so the
104 // correct float result for 66336650.00...01 is rounding up to 66336652. The
105 // correct double is instead 66336650, which when converted to float is
106 // rounded down to 66336648. This means we have to compare against the correct
107 // precision to get the correct result.
109 // TODO: Add support for other rounding modes.
110 int float_precision
= effective_precision
<float>(result_exp
);
111 if (float_precision
>= 2) {
113 mpfr_init2(mpfr_float
, float_precision
);
114 mpfr_strtofr(mpfr_float
, str_ptr
, &out_ptr
, base
, MPFR_RNDN
);
115 float volatile float_result
= mpfr_get_flt(mpfr_float
, MPFR_RNDN
);
116 auto volatile strtof_result
= LIBC_NAMESPACE::strtof(str_ptr
, &out_ptr
);
117 ptrdiff_t strtof_strlen
= out_ptr
- str_ptr
;
118 if (result_strlen
!= strtof_strlen
)
120 // If any result is NaN, all of them should be NaN. We can't use the usual
121 // comparisons because NaN != NaN.
122 if (isnan(float_result
) ^ isnan(strtof_result
))
124 if (!isnan(float_result
) && float_result
!= strtof_result
)
126 mpfr_clear(mpfr_float
);
129 int double_precision
= effective_precision
<double>(result_exp
);
130 if (double_precision
>= 2) {
132 mpfr_init2(mpfr_double
, double_precision
);
133 mpfr_strtofr(mpfr_double
, str_ptr
, &out_ptr
, base
, MPFR_RNDN
);
134 double volatile double_result
= mpfr_get_d(mpfr_double
, MPFR_RNDN
);
135 auto volatile strtod_result
= LIBC_NAMESPACE::strtod(str_ptr
, &out_ptr
);
136 auto volatile atof_result
= LIBC_NAMESPACE::atof(str_ptr
);
137 ptrdiff_t strtod_strlen
= out_ptr
- str_ptr
;
138 if (result_strlen
!= strtod_strlen
)
140 if (isnan(double_result
) ^ isnan(strtod_result
) ||
141 isnan(double_result
) ^ isnan(atof_result
))
143 if (!isnan(double_result
) &&
144 (double_result
!= strtod_result
|| double_result
!= atof_result
))
146 mpfr_clear(mpfr_double
);
149 int long_double_precision
= effective_precision
<long double>(result_exp
);
150 if (long_double_precision
>= 2) {
151 mpfr_t mpfr_long_double
;
152 mpfr_init2(mpfr_long_double
, long_double_precision
);
153 mpfr_strtofr(mpfr_long_double
, str_ptr
, &out_ptr
, base
, MPFR_RNDN
);
154 long double volatile long_double_result
=
155 mpfr_get_ld(mpfr_long_double
, MPFR_RNDN
);
156 auto volatile strtold_result
= LIBC_NAMESPACE::strtold(str_ptr
, &out_ptr
);
157 ptrdiff_t strtold_strlen
= out_ptr
- str_ptr
;
158 if (result_strlen
!= strtold_strlen
)
160 if (isnan(long_double_result
) ^ isnan(strtold_result
))
162 if (!isnan(long_double_result
) && long_double_result
!= strtold_result
)
164 mpfr_clear(mpfr_long_double
);