Skip to content

Commit cb43ae4

Browse files
[libc][fuzzing] Improve printf long double fuzzing (#172113)
Previously we only checked the long double value of the provided double. This meant we didn't check any values near the edge of the long double range, which meant we were missing several bugs. This patch adds a second long double value to check which is generated separately from the double value and can be anywhere in the range.
1 parent 50955d6 commit cb43ae4

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

libc/fuzzing/stdio/printf_float_conv_fuzz.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
8787
// data = raw_data;
8888
// size = sizeof(raw_data);
8989
double num = 0.0;
90+
long double ld_num = 0.0L;
9091
int prec = 0;
9192
int width = 0;
9293

9394
LIBC_NAMESPACE::fputil::FPBits<double>::StorageType raw_num = 0;
95+
LIBC_NAMESPACE::fputil::FPBits<long double>::StorageType ld_raw_num = 0;
9496

9597
// Copy as many bytes of data as will fit into num, prec, and with. Any extras
9698
// are ignored.
@@ -101,16 +103,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
101103
prec = (prec << 8) + data[cur];
102104
} else if (cur < sizeof(raw_num) + sizeof(prec) + sizeof(width)) {
103105
width = (width << 8) + data[cur];
106+
} else if (cur < sizeof(raw_num) + sizeof(prec) + sizeof(width) +
107+
sizeof(ld_raw_num)) {
108+
ld_raw_num = (ld_raw_num << 8) + data[cur];
104109
}
105110
}
106111

107112
num = LIBC_NAMESPACE::fputil::FPBits<double>(raw_num).get_val();
113+
ld_num = LIBC_NAMESPACE::fputil::FPBits<long double>(ld_raw_num).get_val();
108114

109-
// While we could create a "ld_raw_num" from additional bytes, it's much
110-
// easier to stick with simply casting num to long double. This avoids the
111-
// issues around 80 bit long doubles, especially unnormal and pseudo-denormal
112-
// numbers, which MPFR doesn't handle well.
113-
long double ld_num = static_cast<long double>(num);
115+
// checking the same value in double and long double could help find
116+
// mismatches. It also ensures long doubles are being tested even before the
117+
// input data is long enough. Mostly this is here to match previous behavior
118+
// where this was the only long double value checked.
119+
long double num_as_ld = static_cast<long double>(num);
114120

115121
if (width > MAX_SIZE) {
116122
width = MAX_SIZE;
@@ -130,6 +136,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
130136
TestResult result;
131137
if (fmt_arr[cur_fmt][fmt_len - 2] == 'L') {
132138
result = test_vals<long double>(fmt_arr[cur_fmt], ld_num, prec, width);
139+
result = test_vals<long double>(fmt_arr[cur_fmt], num_as_ld, prec, width);
133140
} else {
134141
result = test_vals<double>(fmt_arr[cur_fmt], num, prec, width);
135142
}

0 commit comments

Comments
 (0)