1 // Copyright (c) 2020 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
5 #include <test/fuzz/FuzzedDataProvider.h>
6 #include <test/fuzz/fuzz.h>
7 #include <tinyformat.h>
8 #include <util/strencodings.h>
9 #include <util/translation.h>
10
11 #include <algorithm>
12 #include <cstdint>
13 #include <string>
14 #include <vector>
15
test_one_input(const std::vector<uint8_t> & buffer)16 void test_one_input(const std::vector<uint8_t>& buffer)
17 {
18 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
19 const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
20 const bilingual_str bilingual_string{format_string, format_string};
21
22 const int digits_in_format_specifier = std::count_if(format_string.begin(), format_string.end(), IsDigit);
23
24 // Avoid triggering the following crash bug:
25 // * strprintf("%987654321000000:", 1);
26 //
27 // Avoid triggering the following OOM bug:
28 // * strprintf("%.222222200000000$", 1.1);
29 //
30 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
31 if (format_string.find('%') != std::string::npos && digits_in_format_specifier >= 7) {
32 return;
33 }
34
35 // Avoid triggering the following crash bug:
36 // * strprintf("%1$*1$*", -11111111);
37 //
38 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
39 if (format_string.find('%') != std::string::npos && format_string.find('$') != std::string::npos && format_string.find('*') != std::string::npos && digits_in_format_specifier > 0) {
40 return;
41 }
42
43 // Avoid triggering the following crash bug:
44 // * strprintf("%.1s", (char*)nullptr);
45 //
46 // (void)strprintf(format_string, (char*)nullptr);
47 //
48 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
49
50 try {
51 (void)strprintf(format_string, (signed char*)nullptr);
52 (void)tinyformat::format(bilingual_string, (signed char*)nullptr);
53 } catch (const tinyformat::format_error&) {
54 }
55 try {
56 (void)strprintf(format_string, (unsigned char*)nullptr);
57 (void)tinyformat::format(bilingual_string, (unsigned char*)nullptr);
58 } catch (const tinyformat::format_error&) {
59 }
60 try {
61 (void)strprintf(format_string, (void*)nullptr);
62 (void)tinyformat::format(bilingual_string, (void*)nullptr);
63 } catch (const tinyformat::format_error&) {
64 }
65 try {
66 (void)strprintf(format_string, (bool*)nullptr);
67 (void)tinyformat::format(bilingual_string, (bool*)nullptr);
68 } catch (const tinyformat::format_error&) {
69 }
70 try {
71 (void)strprintf(format_string, (float*)nullptr);
72 (void)tinyformat::format(bilingual_string, (float*)nullptr);
73 } catch (const tinyformat::format_error&) {
74 }
75 try {
76 (void)strprintf(format_string, (double*)nullptr);
77 (void)tinyformat::format(bilingual_string, (double*)nullptr);
78 } catch (const tinyformat::format_error&) {
79 }
80 try {
81 (void)strprintf(format_string, (int16_t*)nullptr);
82 (void)tinyformat::format(bilingual_string, (int16_t*)nullptr);
83 } catch (const tinyformat::format_error&) {
84 }
85 try {
86 (void)strprintf(format_string, (uint16_t*)nullptr);
87 (void)tinyformat::format(bilingual_string, (uint16_t*)nullptr);
88 } catch (const tinyformat::format_error&) {
89 }
90 try {
91 (void)strprintf(format_string, (int32_t*)nullptr);
92 (void)tinyformat::format(bilingual_string, (int32_t*)nullptr);
93 } catch (const tinyformat::format_error&) {
94 }
95 try {
96 (void)strprintf(format_string, (uint32_t*)nullptr);
97 (void)tinyformat::format(bilingual_string, (uint32_t*)nullptr);
98 } catch (const tinyformat::format_error&) {
99 }
100 try {
101 (void)strprintf(format_string, (int64_t*)nullptr);
102 (void)tinyformat::format(bilingual_string, (int64_t*)nullptr);
103 } catch (const tinyformat::format_error&) {
104 }
105 try {
106 (void)strprintf(format_string, (uint64_t*)nullptr);
107 (void)tinyformat::format(bilingual_string, (uint64_t*)nullptr);
108 } catch (const tinyformat::format_error&) {
109 }
110
111 try {
112 switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) {
113 case 0:
114 (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
115 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
116 break;
117 case 1:
118 (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
119 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
120 break;
121 case 2:
122 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
123 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
124 break;
125 case 3:
126 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
127 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
128 break;
129 case 4:
130 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
131 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
132 break;
133 case 5:
134 (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
135 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
136 break;
137 }
138 } catch (const tinyformat::format_error&) {
139 }
140
141 if (format_string.find('%') != std::string::npos && format_string.find('c') != std::string::npos) {
142 // Avoid triggering the following:
143 // * strprintf("%c", 1.31783e+38);
144 // tinyformat.h:244:36: runtime error: 1.31783e+38 is outside the range of representable values of type 'char'
145 return;
146 }
147
148 if (format_string.find('%') != std::string::npos && format_string.find('*') != std::string::npos) {
149 // Avoid triggering the following:
150 // * strprintf("%*", -2.33527e+38);
151 // tinyformat.h:283:65: runtime error: -2.33527e+38 is outside the range of representable values of type 'int'
152 // * strprintf("%*", -2147483648);
153 // 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
154 return;
155 }
156
157 try {
158 switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
159 case 0:
160 (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
161 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
162 break;
163 case 1:
164 (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
165 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
166 break;
167 case 2:
168 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
169 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
170 break;
171 case 3:
172 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
173 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
174 break;
175 case 4:
176 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
177 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
178 break;
179 case 5:
180 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
181 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
182 break;
183 case 6:
184 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
185 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
186 break;
187 case 7:
188 (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
189 (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
190 break;
191 }
192 } catch (const tinyformat::format_error&) {
193 }
194 }
195