brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · b4a8621 Raw
134 lines · cpp
1//===-- printf_fixed_conv_fuzz.cpp ----------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// Fuzzing test for llvm-libc printf %f/e/g/a implementations.10///11//===----------------------------------------------------------------------===//12#include "src/stdio/snprintf.h"13 14#include "include/llvm-libc-macros/stdfix-macros.h"15#include "src/__support/fixed_point/fx_bits.h"16#include "src/__support/fixed_point/fx_rep.h"17 18#include <stddef.h>19#include <stdint.h>20 21#include "utils/MPFRWrapper/mpfr_inc.h"22 23constexpr int MAX_SIZE = 10000;24 25inline bool simple_streq(char *first, char *second, int length) {26  for (int i = 0; i < length; ++i)27    if (first[i] != second[i])28      return false;29 30  return true;31}32 33inline int clamp(int num, int max) {34  if (num > max)35    return max;36  if (num < -max)37    return -max;38  return num;39}40 41enum class TestResult {42  Success,43  BufferSizeFailed,44  LengthsDiffer,45  StringsNotEqual,46};47 48template <typename F>49inline TestResult test_vals(const char *fmt, uint64_t num, int prec,50                            int width) {51  typename LIBC_NAMESPACE::fixed_point::FXRep<F>::StorageType raw_num = num;52 53  auto raw_num_bits = LIBC_NAMESPACE::fixed_point::FXBits<F>(raw_num);54 55  // This needs to be a float with enough bits of precision to hold the fixed56  // point number.57  static_assert(sizeof(long double) > sizeof(long accum));58 59  // build a long double that is equivalent to the fixed point number.60  long double ld_num =61      static_cast<long double>(raw_num_bits.get_integral()) +62      (static_cast<long double>(raw_num_bits.get_fraction()) /63       static_cast<long double>(1ll << raw_num_bits.get_exponent()));64 65  if (raw_num_bits.get_sign())66    ld_num = -ld_num;67 68  // Call snprintf on a nullptr to get the buffer size.69  int buffer_size = LIBC_NAMESPACE::snprintf(nullptr, 0, fmt, width, prec, num);70 71  if (buffer_size < 0)72    return TestResult::BufferSizeFailed;73 74  char *test_buff = new char[buffer_size + 1];75  char *reference_buff = new char[buffer_size + 1];76 77  int test_result = 0;78  int reference_result = 0;79 80  test_result = LIBC_NAMESPACE::snprintf(test_buff, buffer_size + 1, fmt, width,81                                         prec, num);82 83  // The fixed point format is defined to be %f equivalent.84  reference_result = mpfr_snprintf(reference_buff, buffer_size + 1, "%*.*Lf",85                                   width, prec, ld_num);86 87  // All of these calls should return that they wrote the same amount.88  if (test_result != reference_result || test_result != buffer_size)89    return TestResult::LengthsDiffer;90 91  if (!simple_streq(test_buff, reference_buff, buffer_size))92    return TestResult::StringsNotEqual;93 94  delete[] test_buff;95  delete[] reference_buff;96  return TestResult::Success;97}98 99extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {100  // const uint8_t raw_data[] = {0x8d,0x43,0x40,0x0,0x0,0x0,};101  // data = raw_data;102  // size = sizeof(raw_data);103  int prec = 0;104  int width = 0;105 106  LIBC_NAMESPACE::fixed_point::FXRep<long accum>::StorageType raw_num = 0;107 108  // Copy as many bytes of data as will fit into num, prec, and with. Any extras109  // are ignored.110  for (size_t cur = 0; cur < size; ++cur) {111    if (cur < sizeof(raw_num)) {112      raw_num = (raw_num << 8) + data[cur];113    } else if (cur < sizeof(raw_num) + sizeof(prec)) {114      prec = (prec << 8) + data[cur];115    } else if (cur < sizeof(raw_num) + sizeof(prec) + sizeof(width)) {116      width = (width << 8) + data[cur];117    }118  }119 120  width = clamp(width, MAX_SIZE);121  prec = clamp(prec, MAX_SIZE);122 123  TestResult result;124  result = test_vals<long accum>("%*.*lk", raw_num, prec, width);125  if (result != TestResult::Success)126    __builtin_trap();127 128  result = test_vals<unsigned long accum>("%*.*lK", raw_num, prec, width);129  if (result != TestResult::Success)130    __builtin_trap();131 132  return 0;133}134