strprintf.cpp raw
1 // Copyright (c) 2020-present 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 <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 template <typename... Args>
18 void fuzz_fmt(const std::string& fmt, const Args&... args)
19 {
20 (void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
21 }
22
23 FUZZ_TARGET(str_printf)
24 {
25 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
26 const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
27
28 const int digits_in_format_specifier = std::count_if(format_string.begin(), format_string.end(), IsDigit);
29
30 // Avoid triggering the following crash bug:
31 // * strprintf("%987654321000000:", 1);
32 //
33 // Avoid triggering the following OOM bug:
34 // * strprintf("%.222222200000000$", 1.1);
35 //
36 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
37 if (format_string.find('%') != std::string::npos && digits_in_format_specifier >= 7) {
38 return;
39 }
40
41 // Avoid triggering the following crash bug:
42 // * strprintf("%1$*1$*", -11111111);
43 //
44 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
45 if (format_string.find('%') != std::string::npos && format_string.find('$') != std::string::npos && format_string.find('*') != std::string::npos && digits_in_format_specifier > 0) {
46 return;
47 }
48
49 // Avoid triggering the following crash bug:
50 // * strprintf("%.1s", (char*)nullptr);
51 //
52 // (void)strprintf(format_string, (char*)nullptr);
53 //
54 // Upstream bug report: https://github.com/c42f/tinyformat/issues/70
55
56 try {
57 CallOneOf(
58 fuzzed_data_provider,
59 [&] {
60 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
61 },
62 [&] {
63 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
64 },
65 [&] {
66 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
67 },
68 [&] {
69 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
70 },
71 [&] {
72 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
73 },
74 [&] {
75 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeBool());
76 });
77 } catch (const tinyformat::format_error&) {
78 }
79
80 if (format_string.find('%') != std::string::npos && format_string.find('c') != std::string::npos) {
81 // Avoid triggering the following:
82 // * strprintf("%c", 1.31783e+38);
83 // tinyformat.h:244:36: runtime error: 1.31783e+38 is outside the range of representable values of type 'char'
84 return;
85 }
86
87 if (format_string.find('%') != std::string::npos && format_string.find('*') != std::string::npos) {
88 // Avoid triggering the following:
89 // * strprintf("%*", -2.33527e+38);
90 // tinyformat.h:283:65: runtime error: -2.33527e+38 is outside the range of representable values of type 'int'
91 // * strprintf("%*", -2147483648);
92 // 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
93 return;
94 }
95
96 try {
97 CallOneOf(
98 fuzzed_data_provider,
99 [&] {
100 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
101 },
102 [&] {
103 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
104 },
105 [&] {
106 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
107 },
108 [&] {
109 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
110 },
111 [&] {
112 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
113 },
114 [&] {
115 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
116 },
117 [&] {
118 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
119 },
120 [&] {
121 fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
122 });
123 } catch (const tinyformat::format_error&) {
124 }
125 }
126