Bitcoin Core 28.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
17template <typename... Args>
18void fuzz_fmt(const std::string& fmt, const Args&... args)
19{
20 (void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
21}
22
23FUZZ_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 {
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 {
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}
ArgsManager & args
Definition: bitcoind.cpp:277
std::string ConsumeRandomLengthString(size_t max_length)
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
constexpr bool IsDigit(char c)
Tests if the given character is a decimal digit.
Definition: strencodings.h:150
FUZZ_TARGET(str_printf)
Definition: strprintf.cpp:23
void fuzz_fmt(const std::string &fmt, const Args &... args)
Definition: strprintf.cpp:18
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:35