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