Branch data Line data Source code
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 : :
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 : 1607 : void fuzz_fmt(const std::string& fmt, const Args&... args)
19 : : {
20 : 1607 : (void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
21 : 1200 : }
22 : :
23 [ + - ]: 1278 : FUZZ_TARGET(str_printf)
24 : : {
25 : 864 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
26 : 864 : const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
27 : :
28 [ + - ]: 864 : 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 [ + + + + ]: 864 : 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 [ + + + + : 862 : 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 : 861 : try {
57 [ + + ]: 861 : CallOneOf(
58 : : fuzzed_data_provider,
59 : 337 : [&] {
60 [ + + ]: 337 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
61 : 271 : },
62 : 87 : [&] {
63 [ + + ]: 87 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
64 : 60 : },
65 : 116 : [&] {
66 : 116 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
67 : 73 : },
68 : 134 : [&] {
69 : 134 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
70 : 95 : },
71 : 104 : [&] {
72 : 104 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
73 : 69 : },
74 : 83 : [&] {
75 : 83 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeBool());
76 : 58 : });
77 [ - + ]: 235 : } catch (const tinyformat::format_error&) {
78 : 235 : }
79 : :
80 [ + + + + ]: 861 : 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 [ + + + + ]: 808 : 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 : 746 : try {
97 [ + + ]: 746 : CallOneOf(
98 : : fuzzed_data_provider,
99 : 398 : [&] {
100 : 398 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
101 : 326 : },
102 : 58 : [&] {
103 : 58 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
104 : 39 : },
105 : 47 : [&] {
106 : 47 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
107 : 34 : },
108 : 41 : [&] {
109 : 41 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
110 : 30 : },
111 : 55 : [&] {
112 : 55 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
113 : 41 : },
114 : 49 : [&] {
115 : 49 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
116 : 29 : },
117 : 32 : [&] {
118 : 32 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
119 : 18 : },
120 : 66 : [&] {
121 : 66 : fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
122 : 57 : });
123 [ - + ]: 172 : } catch (const tinyformat::format_error&) {
124 : 172 : }
125 : 864 : }
|