13a66446aSMichael Jones //===-- strtofloat_fuzz.cpp -----------------------------------------------===// 23a66446aSMichael Jones // 33a66446aSMichael Jones // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43a66446aSMichael Jones // See https://llvm.org/LICENSE.txt for license information. 53a66446aSMichael Jones // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63a66446aSMichael Jones // 73a66446aSMichael Jones //===----------------------------------------------------------------------===// 83a66446aSMichael Jones /// 93a66446aSMichael Jones /// Fuzzing test for llvm-libc atof implementation. 103a66446aSMichael Jones /// 113a66446aSMichael Jones //===----------------------------------------------------------------------===// 123a66446aSMichael Jones #include "src/stdlib/atof.h" 133a66446aSMichael Jones #include "src/stdlib/strtod.h" 143a66446aSMichael Jones #include "src/stdlib/strtof.h" 153a66446aSMichael Jones #include "src/stdlib/strtold.h" 16ae3b59e6SMichael Jones 17c2399147SGuillaume Chatelet #include "src/__support/FPUtil/FPBits.h" 18cfbcbc8fSMichael Jones 195748ad84Slntue #include "hdr/math_macros.h" 203a66446aSMichael Jones #include <stddef.h> 213a66446aSMichael Jones #include <stdint.h> 223a66446aSMichael Jones 23ae3b59e6SMichael Jones #include "utils/MPFRWrapper/mpfr_inc.h" 24ae3b59e6SMichael Jones 25c09e6905SGuillaume Chatelet using LIBC_NAMESPACE::fputil::FPBits; 26cfbcbc8fSMichael Jones 272cb47319SMichael Jones // This function calculates the effective precision for a given float type and 282cb47319SMichael Jones // exponent. Subnormals have a lower effective precision since they don't 292cb47319SMichael Jones // necessarily use all of the bits of the mantissa. 302ff8094eSMichael Jones template <typename F> inline constexpr int effective_precision(int exponent) { 316b02d2f8SGuillaume Chatelet const int full_precision = FPBits<F>::FRACTION_LEN + 1; 322cb47319SMichael Jones 332cb47319SMichael Jones // This is intended to be 0 when the exponent is the lowest normal and 342cb47319SMichael Jones // increase as the exponent's magnitude increases. 35c09e6905SGuillaume Chatelet const int bits_below_normal = (-exponent) - (FPBits<F>::EXP_BIAS - 1); 362cb47319SMichael Jones 372cb47319SMichael Jones // The precision should be the normal, full precision, minus the bits lost 382cb47319SMichael Jones // by this being a subnormal, minus one for the implicit leading one. 392ff8094eSMichael Jones const int bits_if_subnormal = full_precision - bits_below_normal - 1; 402ff8094eSMichael Jones 412ff8094eSMichael Jones if (bits_below_normal >= 0) { 422ff8094eSMichael Jones return bits_if_subnormal; 432cb47319SMichael Jones } 442cb47319SMichael Jones return full_precision; 452cb47319SMichael Jones } 462cb47319SMichael Jones 473a66446aSMichael Jones extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 482ff8094eSMichael Jones // const char newstr[] = "123"; 492ff8094eSMichael Jones // data = reinterpret_cast<const uint8_t *>(newstr); 502ff8094eSMichael Jones // size = sizeof(newstr); 513a66446aSMichael Jones uint8_t *container = new uint8_t[size + 1]; 523a66446aSMichael Jones if (!container) 533a66446aSMichael Jones __builtin_trap(); 543a66446aSMichael Jones size_t i; 553a66446aSMichael Jones 56ae3b59e6SMichael Jones for (i = 0; i < size; ++i) { 57ae3b59e6SMichael Jones // MPFR's strtofr uses "@" as a base-independent exponent symbol 58ae3b59e6SMichael Jones if (data[i] != '@') 593a66446aSMichael Jones container[i] = data[i]; 60ae3b59e6SMichael Jones else { 61ae3b59e6SMichael Jones container[i] = '#'; 62ae3b59e6SMichael Jones } 63ae3b59e6SMichael Jones } 643a66446aSMichael Jones container[size] = '\0'; // Add null terminator to container. 653a66446aSMichael Jones 663a66446aSMichael Jones const char *str_ptr = reinterpret_cast<const char *>(container); 673a66446aSMichael Jones 683a66446aSMichael Jones char *out_ptr = nullptr; 693a66446aSMichael Jones 70cfbcbc8fSMichael Jones size_t base = 0; 71cfbcbc8fSMichael Jones 722cb47319SMichael Jones // This is just used to determine the base and precision. 73ae3b59e6SMichael Jones mpfr_t result; 74ae3b59e6SMichael Jones mpfr_init2(result, 256); 75ae3b59e6SMichael Jones mpfr_t bin_result; 76ae3b59e6SMichael Jones mpfr_init2(bin_result, 256); 77ae3b59e6SMichael Jones mpfr_strtofr(result, str_ptr, &out_ptr, 0 /* base */, MPFR_RNDN); 78ae3b59e6SMichael Jones ptrdiff_t result_strlen = out_ptr - str_ptr; 79ae3b59e6SMichael Jones mpfr_strtofr(bin_result, str_ptr, &out_ptr, 2 /* base */, MPFR_RNDN); 80ae3b59e6SMichael Jones ptrdiff_t bin_result_strlen = out_ptr - str_ptr; 81ae3b59e6SMichael Jones 82ae3b59e6SMichael Jones long double bin_result_ld = mpfr_get_ld(bin_result, MPFR_RNDN); 83ae3b59e6SMichael Jones long double result_ld = mpfr_get_ld(result, MPFR_RNDN); 84ae3b59e6SMichael Jones 85ae3b59e6SMichael Jones // This detects if mpfr's strtofr selected a base of 2, which libc does not 86ae3b59e6SMichael Jones // support. If a base 2 decoding is detected, it is replaced by a base 10 87ae3b59e6SMichael Jones // decoding. 88ae3b59e6SMichael Jones if ((bin_result_ld != 0.0 || bin_result_strlen == result_strlen) && 89ae3b59e6SMichael Jones bin_result_ld == result_ld) { 90ae3b59e6SMichael Jones mpfr_strtofr(result, str_ptr, &out_ptr, 10 /* base */, MPFR_RNDN); 91ae3b59e6SMichael Jones result_strlen = out_ptr - str_ptr; 92cfbcbc8fSMichael Jones base = 10; 93ae3b59e6SMichael Jones } 94ae3b59e6SMichael Jones 952cb47319SMichael Jones auto result_exp = mpfr_get_exp(result); 962cb47319SMichael Jones 97cfbcbc8fSMichael Jones mpfr_clear(result); 98cfbcbc8fSMichael Jones mpfr_clear(bin_result); 99cfbcbc8fSMichael Jones 100cfbcbc8fSMichael Jones // These must be calculated with the correct precision, and not any more, to 101cfbcbc8fSMichael Jones // prevent numbers like 66336650.00...01 (many zeroes) from causing an issue. 102cfbcbc8fSMichael Jones // 66336650 is exactly between two float values (66336652 and 66336648) so the 103cfbcbc8fSMichael Jones // correct float result for 66336650.00...01 is rounding up to 66336652. The 104cfbcbc8fSMichael Jones // correct double is instead 66336650, which when converted to float is 105cfbcbc8fSMichael Jones // rounded down to 66336648. This means we have to compare against the correct 106cfbcbc8fSMichael Jones // precision to get the correct result. 1072cb47319SMichael Jones 108cfbcbc8fSMichael Jones // TODO: Add support for other rounding modes. 1092ff8094eSMichael Jones int float_precision = effective_precision<float>(result_exp); 1102ff8094eSMichael Jones if (float_precision >= 2) { 1112ff8094eSMichael Jones mpfr_t mpfr_float; 1122ff8094eSMichael Jones mpfr_init2(mpfr_float, float_precision); 113cfbcbc8fSMichael Jones mpfr_strtofr(mpfr_float, str_ptr, &out_ptr, base, MPFR_RNDN); 114cfbcbc8fSMichael Jones float volatile float_result = mpfr_get_flt(mpfr_float, MPFR_RNDN); 115b6bc9d72SGuillaume Chatelet auto volatile strtof_result = LIBC_NAMESPACE::strtof(str_ptr, &out_ptr); 116ae3b59e6SMichael Jones ptrdiff_t strtof_strlen = out_ptr - str_ptr; 117ae3b59e6SMichael Jones if (result_strlen != strtof_strlen) 1183a66446aSMichael Jones __builtin_trap(); 1192ff8094eSMichael Jones // If any result is NaN, all of them should be NaN. We can't use the usual 1202ff8094eSMichael Jones // comparisons because NaN != NaN. 121*dfdef2cbSlntue if (FPBits<float>(float_result).is_nan() != 122*dfdef2cbSlntue FPBits<float>(strtof_result).is_nan()) 1232ff8094eSMichael Jones __builtin_trap(); 124*dfdef2cbSlntue if (!FPBits<float>(float_result).is_nan() && float_result != strtof_result) 1252ff8094eSMichael Jones __builtin_trap(); 1262ff8094eSMichael Jones mpfr_clear(mpfr_float); 1272ff8094eSMichael Jones } 1282ff8094eSMichael Jones 1292ff8094eSMichael Jones int double_precision = effective_precision<double>(result_exp); 1302ff8094eSMichael Jones if (double_precision >= 2) { 1312ff8094eSMichael Jones mpfr_t mpfr_double; 1322ff8094eSMichael Jones mpfr_init2(mpfr_double, double_precision); 1332ff8094eSMichael Jones mpfr_strtofr(mpfr_double, str_ptr, &out_ptr, base, MPFR_RNDN); 1342ff8094eSMichael Jones double volatile double_result = mpfr_get_d(mpfr_double, MPFR_RNDN); 135b6bc9d72SGuillaume Chatelet auto volatile strtod_result = LIBC_NAMESPACE::strtod(str_ptr, &out_ptr); 136b6bc9d72SGuillaume Chatelet auto volatile atof_result = LIBC_NAMESPACE::atof(str_ptr); 137ae3b59e6SMichael Jones ptrdiff_t strtod_strlen = out_ptr - str_ptr; 138ae3b59e6SMichael Jones if (result_strlen != strtod_strlen) 1393a66446aSMichael Jones __builtin_trap(); 140*dfdef2cbSlntue if (FPBits<double>(double_result).is_nan() != 141*dfdef2cbSlntue FPBits<double>(strtod_result).is_nan() || 142*dfdef2cbSlntue FPBits<double>(double_result).is_nan() != 143*dfdef2cbSlntue FPBits<double>(atof_result).is_nan()) 1442ff8094eSMichael Jones __builtin_trap(); 145*dfdef2cbSlntue if (!FPBits<double>(double_result).is_nan() && 1462ff8094eSMichael Jones (double_result != strtod_result || double_result != atof_result)) 1472ff8094eSMichael Jones __builtin_trap(); 1482ff8094eSMichael Jones mpfr_clear(mpfr_double); 1492ff8094eSMichael Jones } 1502ff8094eSMichael Jones 1512ff8094eSMichael Jones int long_double_precision = effective_precision<long double>(result_exp); 1522ff8094eSMichael Jones if (long_double_precision >= 2) { 1532ff8094eSMichael Jones mpfr_t mpfr_long_double; 1542ff8094eSMichael Jones mpfr_init2(mpfr_long_double, long_double_precision); 1552ff8094eSMichael Jones mpfr_strtofr(mpfr_long_double, str_ptr, &out_ptr, base, MPFR_RNDN); 1562ff8094eSMichael Jones long double volatile long_double_result = 1572ff8094eSMichael Jones mpfr_get_ld(mpfr_long_double, MPFR_RNDN); 158b6bc9d72SGuillaume Chatelet auto volatile strtold_result = LIBC_NAMESPACE::strtold(str_ptr, &out_ptr); 159ae3b59e6SMichael Jones ptrdiff_t strtold_strlen = out_ptr - str_ptr; 160ae3b59e6SMichael Jones if (result_strlen != strtold_strlen) 1613a66446aSMichael Jones __builtin_trap(); 162*dfdef2cbSlntue if (FPBits<long double>(long_double_result).is_nan() ^ 163*dfdef2cbSlntue FPBits<long double>(strtold_result).is_nan()) 164ae3b59e6SMichael Jones __builtin_trap(); 165*dfdef2cbSlntue if (!FPBits<long double>(long_double_result).is_nan() && 166*dfdef2cbSlntue long_double_result != strtold_result) 167ae3b59e6SMichael Jones __builtin_trap(); 1682ff8094eSMichael Jones mpfr_clear(mpfr_long_double); 16962e7bdd2SMichael Jones } 17062e7bdd2SMichael Jones 1713a66446aSMichael Jones delete[] container; 1723a66446aSMichael Jones return 0; 1733a66446aSMichael Jones } 174