diff options
author | Michael Jones <michaelrj@google.com> | 2023-07-12 15:21:52 -0700 |
---|---|---|
committer | Michael Jones <michaelrj@google.com> | 2023-07-18 16:28:22 -0700 |
commit | 2ff8094e328001b37eda8c71306c557b842955ae (patch) | |
tree | c6a9d3fdc55d616af349a05efe294d48dfcd3617 /libc/fuzzing | |
parent | 5ce5e983f82c802e44faa8ed42d605d70c045ba9 (diff) | |
download | llvm-2ff8094e328001b37eda8c71306c557b842955ae.zip llvm-2ff8094e328001b37eda8c71306c557b842955ae.tar.gz llvm-2ff8094e328001b37eda8c71306c557b842955ae.tar.bz2 |
[libc] Set min precision for strtofloat fuzz
MPFR has a minimum precision of 2, but the strtofloat fuzz sometimes
would request a precision of 1 for the case of the minimum subnormal.
This patch tells the fuzzer to ignore any case where the precision would
go below 2.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D155130
Diffstat (limited to 'libc/fuzzing')
-rw-r--r-- | libc/fuzzing/stdlib/strtofloat_fuzz.cpp | 115 |
1 files changed, 62 insertions, 53 deletions
diff --git a/libc/fuzzing/stdlib/strtofloat_fuzz.cpp b/libc/fuzzing/stdlib/strtofloat_fuzz.cpp index 1170b41..5ef506a 100644 --- a/libc/fuzzing/stdlib/strtofloat_fuzz.cpp +++ b/libc/fuzzing/stdlib/strtofloat_fuzz.cpp @@ -27,23 +27,28 @@ using __llvm_libc::fputil::FloatProperties; // This function calculates the effective precision for a given float type and // exponent. Subnormals have a lower effective precision since they don't // necessarily use all of the bits of the mantissa. -template <typename F> inline int effective_precision(int exponent) { - int full_precision = FloatProperties<F>::MANTISSA_PRECISION; +template <typename F> inline constexpr int effective_precision(int exponent) { + const int full_precision = FloatProperties<F>::MANTISSA_PRECISION; // This is intended to be 0 when the exponent is the lowest normal and // increase as the exponent's magnitude increases. - int bits_below_normal = (-exponent) - (FloatProperties<F>::EXPONENT_BIAS - 1); + const int bits_below_normal = + (-exponent) - (FloatProperties<F>::EXPONENT_BIAS - 1); - // This comparison is optimized out by the compiler. - if (bits_below_normal >= 0 && bits_below_normal < full_precision - 1) { - // The precision should be the normal, full precision, minus the bits lost - // by this being a subnormal, minus one for the implicit leading one. - return full_precision - bits_below_normal - 1; + // The precision should be the normal, full precision, minus the bits lost + // by this being a subnormal, minus one for the implicit leading one. + const int bits_if_subnormal = full_precision - bits_below_normal - 1; + + if (bits_below_normal >= 0) { + return bits_if_subnormal; } return full_precision; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // const char newstr[] = "123"; + // data = reinterpret_cast<const uint8_t *>(newstr); + // size = sizeof(newstr); uint8_t *container = new uint8_t[size + 1]; if (!container) __builtin_trap(); @@ -101,58 +106,62 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { // rounded down to 66336648. This means we have to compare against the correct // precision to get the correct result. - mpfr_t mpfr_float; - mpfr_init2(mpfr_float, effective_precision<float>(result_exp)); - - mpfr_t mpfr_double; - mpfr_init2(mpfr_double, effective_precision<double>(result_exp)); - - mpfr_t mpfr_long_double; - mpfr_init2(mpfr_long_double, effective_precision<long double>(result_exp)); - // TODO: Add support for other rounding modes. - mpfr_strtofr(mpfr_float, str_ptr, &out_ptr, base, MPFR_RNDN); - mpfr_strtofr(mpfr_double, str_ptr, &out_ptr, base, MPFR_RNDN); - mpfr_strtofr(mpfr_long_double, str_ptr, &out_ptr, base, MPFR_RNDN); - - float volatile float_result = mpfr_get_flt(mpfr_float, MPFR_RNDN); - double volatile double_result = mpfr_get_d(mpfr_double, MPFR_RNDN); - long double volatile long_double_result = - mpfr_get_ld(mpfr_long_double, MPFR_RNDN); - - mpfr_clear(mpfr_float); - mpfr_clear(mpfr_double); - mpfr_clear(mpfr_long_double); - - auto volatile atof_output = __llvm_libc::atof(str_ptr); - auto volatile strtof_output = __llvm_libc::strtof(str_ptr, &out_ptr); - ptrdiff_t strtof_strlen = out_ptr - str_ptr; - if (result_strlen != strtof_strlen) - __builtin_trap(); - auto volatile strtod_output = __llvm_libc::strtod(str_ptr, &out_ptr); - ptrdiff_t strtod_strlen = out_ptr - str_ptr; - if (result_strlen != strtod_strlen) - __builtin_trap(); - auto volatile strtold_output = __llvm_libc::strtold(str_ptr, &out_ptr); - ptrdiff_t strtold_strlen = out_ptr - str_ptr; - if (result_strlen != strtold_strlen) - __builtin_trap(); + int float_precision = effective_precision<float>(result_exp); + if (float_precision >= 2) { + mpfr_t mpfr_float; + mpfr_init2(mpfr_float, float_precision); + mpfr_strtofr(mpfr_float, str_ptr, &out_ptr, base, MPFR_RNDN); + float volatile float_result = mpfr_get_flt(mpfr_float, MPFR_RNDN); + auto volatile strtof_result = __llvm_libc::strtof(str_ptr, &out_ptr); + ptrdiff_t strtof_strlen = out_ptr - str_ptr; + if (result_strlen != strtof_strlen) + __builtin_trap(); + // If any result is NaN, all of them should be NaN. We can't use the usual + // comparisons because NaN != NaN. + if (isnan(float_result) ^ isnan(strtof_result)) + __builtin_trap(); + if (!isnan(float_result) && float_result != strtof_result) + __builtin_trap(); + mpfr_clear(mpfr_float); + } - // If any result is NaN, all of them should be NaN. We can't use the usual - // comparisons because NaN != NaN. - if (isnan(float_result)) { - if (!(isnan(atof_output) && isnan(strtof_output) && isnan(strtod_output) && - isnan(strtold_output))) + int double_precision = effective_precision<double>(result_exp); + if (double_precision >= 2) { + mpfr_t mpfr_double; + mpfr_init2(mpfr_double, double_precision); + mpfr_strtofr(mpfr_double, str_ptr, &out_ptr, base, MPFR_RNDN); + double volatile double_result = mpfr_get_d(mpfr_double, MPFR_RNDN); + auto volatile strtod_result = __llvm_libc::strtod(str_ptr, &out_ptr); + auto volatile atof_result = __llvm_libc::atof(str_ptr); + ptrdiff_t strtod_strlen = out_ptr - str_ptr; + if (result_strlen != strtod_strlen) __builtin_trap(); - } else { - if (double_result != atof_output) + if (isnan(double_result) ^ isnan(strtod_result) || + isnan(double_result) ^ isnan(atof_result)) __builtin_trap(); - if (float_result != strtof_output) + if (!isnan(double_result) && + (double_result != strtod_result || double_result != atof_result)) + __builtin_trap(); + mpfr_clear(mpfr_double); + } + + int long_double_precision = effective_precision<long double>(result_exp); + if (long_double_precision >= 2) { + mpfr_t mpfr_long_double; + mpfr_init2(mpfr_long_double, long_double_precision); + mpfr_strtofr(mpfr_long_double, str_ptr, &out_ptr, base, MPFR_RNDN); + long double volatile long_double_result = + mpfr_get_ld(mpfr_long_double, MPFR_RNDN); + auto volatile strtold_result = __llvm_libc::strtold(str_ptr, &out_ptr); + ptrdiff_t strtold_strlen = out_ptr - str_ptr; + if (result_strlen != strtold_strlen) __builtin_trap(); - if (double_result != strtod_output) + if (isnan(long_double_result) ^ isnan(strtold_result)) __builtin_trap(); - if (long_double_result != strtold_output) + if (!isnan(long_double_result) && long_double_result != strtold_result) __builtin_trap(); + mpfr_clear(mpfr_long_double); } delete[] container; |