Bitcoin Core  22.99.0
P2P Digital Currency
strprintf.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-2021 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 #include <test/fuzz/fuzz.h>
7 #include <test/fuzz/util.h>
8 #include <tinyformat.h>
9 #include <util/strencodings.h>
10 #include <util/translation.h>
11 
12 #include <algorithm>
13 #include <cstdint>
14 #include <string>
15 #include <vector>
16 
17 FUZZ_TARGET(str_printf)
18 {
19  FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
20  const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
21  const bilingual_str bilingual_string{format_string, format_string};
22 
23  const int digits_in_format_specifier = std::count_if(format_string.begin(), format_string.end(), IsDigit);
24 
25  // Avoid triggering the following crash bug:
26  // * strprintf("%987654321000000:", 1);
27  //
28  // Avoid triggering the following OOM bug:
29  // * strprintf("%.222222200000000$", 1.1);
30  //
31  // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
32  if (format_string.find('%') != std::string::npos && digits_in_format_specifier >= 7) {
33  return;
34  }
35 
36  // Avoid triggering the following crash bug:
37  // * strprintf("%1$*1$*", -11111111);
38  //
39  // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
40  if (format_string.find('%') != std::string::npos && format_string.find('$') != std::string::npos && format_string.find('*') != std::string::npos && digits_in_format_specifier > 0) {
41  return;
42  }
43 
44  // Avoid triggering the following crash bug:
45  // * strprintf("%.1s", (char*)nullptr);
46  //
47  // (void)strprintf(format_string, (char*)nullptr);
48  //
49  // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
50 
51  try {
52  CallOneOf(
53  fuzzed_data_provider,
54  [&] {
55  (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
56  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
57  },
58  [&] {
59  (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
60  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
61  },
62  [&] {
63  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
64  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
65  },
66  [&] {
67  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
68  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
69  },
70  [&] {
71  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
72  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
73  },
74  [&] {
75  (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
76  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
77  });
78  } catch (const tinyformat::format_error&) {
79  }
80 
81  if (format_string.find('%') != std::string::npos && format_string.find('c') != std::string::npos) {
82  // Avoid triggering the following:
83  // * strprintf("%c", 1.31783e+38);
84  // tinyformat.h:244:36: runtime error: 1.31783e+38 is outside the range of representable values of type 'char'
85  return;
86  }
87 
88  if (format_string.find('%') != std::string::npos && format_string.find('*') != std::string::npos) {
89  // Avoid triggering the following:
90  // * strprintf("%*", -2.33527e+38);
91  // tinyformat.h:283:65: runtime error: -2.33527e+38 is outside the range of representable values of type 'int'
92  // * strprintf("%*", -2147483648);
93  // tinyformat.h:763:25: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
94  return;
95  }
96 
97  try {
98  CallOneOf(
99  fuzzed_data_provider,
100  [&] {
101  (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
102  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
103  },
104  [&] {
105  (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
106  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
107  },
108  [&] {
109  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
110  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
111  },
112  [&] {
113  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
114  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
115  },
116  [&] {
117  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
118  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
119  },
120  [&] {
121  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
122  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
123  },
124  [&] {
125  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
126  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
127  },
128  [&] {
129  (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
130  (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
131  });
132  } catch (const tinyformat::format_error&) {
133  }
134 }
tinyformat::format
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1062
bilingual_str
Bilingual messages:
Definition: translation.h:16
util.h
FuzzedDataProvider::ConsumeRandomLengthString
std::string ConsumeRandomLengthString(size_t max_length)
Definition: FuzzedDataProvider.h:152
FuzzedDataProvider::ConsumeFloatingPoint
T ConsumeFloatingPoint()
Definition: FuzzedDataProvider.h:239
tinyformat.h
strencodings.h
CallOneOf
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:40
FuzzedDataProvider.h
tinyformat::format_error
Definition: tinyformat.h:182
IsDigit
constexpr bool IsDigit(char c)
Tests if the given character is a decimal digit.
Definition: strencodings.h:77
FUZZ_TARGET
FUZZ_TARGET(str_printf)
Definition: strprintf.cpp:17
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
translation.h
fuzz.h
FuzzedDataProvider
Definition: FuzzedDataProvider.h:31
FuzzedDataProvider::ConsumeIntegral
T ConsumeIntegral()
Definition: FuzzedDataProvider.h:194
FuzzedDataProvider::ConsumeBool
bool ConsumeBool()
Definition: FuzzedDataProvider.h:288