1 //===-- printf_fixed_conv_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 printf %f/e/g/a implementations.
11 //===----------------------------------------------------------------------===//
12 #include "src/stdio/snprintf.h"
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"
21 #include "utils/MPFRWrapper/mpfr_inc.h"
23 constexpr int MAX_SIZE
= 10000;
25 inline bool simple_streq(char *first
, char *second
, int length
) {
26 for (int i
= 0; i
< length
; ++i
)
27 if (first
[i
] != second
[i
])
33 inline int clamp(int num
, int max
) {
41 enum class TestResult
{
49 inline TestResult
test_vals(const char *fmt
, uint64_t num
, int prec
,
51 typename
LIBC_NAMESPACE::fixed_point::FXRep
<F
>::StorageType raw_num
= num
;
53 auto raw_num_bits
= LIBC_NAMESPACE::fixed_point::FXBits
<F
>(raw_num
);
55 // This needs to be a float with enough bits of precision to hold the fixed
57 static_assert(sizeof(long double) > sizeof(long accum
));
59 // build a long double that is equivalent to the fixed point number.
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()));
65 if (raw_num_bits
.get_sign())
68 // Call snprintf on a nullptr to get the buffer size.
69 int buffer_size
= LIBC_NAMESPACE::snprintf(nullptr, 0, fmt
, width
, prec
, num
);
72 return TestResult::BufferSizeFailed
;
74 char *test_buff
= new char[buffer_size
+ 1];
75 char *reference_buff
= new char[buffer_size
+ 1];
78 int reference_result
= 0;
80 test_result
= LIBC_NAMESPACE::snprintf(test_buff
, buffer_size
+ 1, fmt
, width
,
83 // The fixed point format is defined to be %f equivalent.
84 reference_result
= mpfr_snprintf(reference_buff
, buffer_size
+ 1, "%*.*Lf",
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
;
91 if (!simple_streq(test_buff
, reference_buff
, buffer_size
))
92 return TestResult::StringsNotEqual
;
95 delete[] reference_buff
;
96 return TestResult::Success
;
99 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data
, size_t size
) {
100 // const uint8_t raw_data[] = {0x8d,0x43,0x40,0x0,0x0,0x0,};
102 // size = sizeof(raw_data);
106 LIBC_NAMESPACE::fixed_point::FXRep
<long accum
>::StorageType raw_num
= 0;
108 // Copy as many bytes of data as will fit into num, prec, and with. Any extras
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
];
120 width
= clamp(width
, MAX_SIZE
);
121 prec
= clamp(prec
, MAX_SIZE
);
124 result
= test_vals
<long accum
>("%*.*lk", raw_num
, prec
, width
);
125 if (result
!= TestResult::Success
)
128 result
= test_vals
<unsigned long accum
>("%*.*lK", raw_num
, prec
, width
);
129 if (result
!= TestResult::Success
)