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 }