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