From fa3efb5729091a36a0e82316e9e4b7c09115dc2e Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Sat, 7 Dec 2024 11:49:48 +0100 Subject: [PATCH] refactor: Introduce struct to hold a runtime format string This brings the format types closer to the standard library types: * FormatStringCheck corresponds to std::basic_format_string, with compile-time checks done via ConstevalFormatString * RuntimeFormat corresponds to std::runtime_format, with no compile-time checks done. Also, it documents where no compile-time checks are done. --- src/test/fuzz/strprintf.cpp | 34 ++++++++++++++++++++-------------- src/test/fuzz/util/wallet.h | 2 +- src/test/util_string_tests.cpp | 2 +- src/tinyformat.h | 13 ++++++++++--- src/util/translation.h | 2 +- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp index be40e88cdd..c7f24fbdb4 100644 --- a/src/test/fuzz/strprintf.cpp +++ b/src/test/fuzz/strprintf.cpp @@ -14,6 +14,12 @@ #include #include +template +void fuzz_fmt(const std::string& fmt, const Args&... args) +{ + (void)tfm::format(tfm::RuntimeFormat{fmt}, args...); +} + FUZZ_TARGET(str_printf) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); @@ -51,22 +57,22 @@ FUZZ_TARGET(str_printf) CallOneOf( fuzzed_data_provider, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeBool()); }); } catch (const tinyformat::format_error&) { } @@ -91,28 +97,28 @@ FUZZ_TARGET(str_printf) CallOneOf( fuzzed_data_provider, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }, [&] { - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral()); }); } catch (const tinyformat::format_error&) { } diff --git a/src/test/fuzz/util/wallet.h b/src/test/fuzz/util/wallet.h index 8b55b7a985..1f04b5dbf1 100644 --- a/src/test/fuzz/util/wallet.h +++ b/src/test/fuzz/util/wallet.h @@ -46,7 +46,7 @@ struct FuzzedWallet { for (const std::string& desc_fmt : DESCS) { for (bool internal : {true, false}) { - const auto descriptor{(strprintf)(desc_fmt, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})}; + const auto descriptor{strprintf(tfm::RuntimeFormat{desc_fmt}, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})}; FlatSigningProvider keys; std::string error; diff --git a/src/test/util_string_tests.cpp b/src/test/util_string_tests.cpp index 340c650fe3..65ee140b6e 100644 --- a/src/test/util_string_tests.cpp +++ b/src/test/util_string_tests.cpp @@ -16,7 +16,7 @@ template void TfmFormatZeroes(const std::string& fmt) { std::apply([&](auto... args) { - (void)tfm::format(fmt, args...); + (void)tfm::format(tfm::RuntimeFormat{fmt}, args...); }, std::array{}); } diff --git a/src/tinyformat.h b/src/tinyformat.h index 0d0e9149cc..29b0f9e3ea 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -142,6 +142,7 @@ namespace tfm = tinyformat; //------------------------------------------------------------------------------ // Implementation details. #include +#include // Added for Bitcoin Core #include #include #include // Added for Bitcoin Core @@ -179,13 +180,19 @@ namespace tfm = tinyformat; namespace tinyformat { +// Added for Bitcoin Core. Similar to std::runtime_format from C++26. +struct RuntimeFormat { + const std::string& fmt; // Not a string view, because tinyformat requires a c_str + explicit RuntimeFormat(LIFETIMEBOUND const std::string& str) : fmt{str} {} +}; + // Added for Bitcoin Core. Wrapper for checking format strings at compile time. -// Unlike ConstevalFormatString this supports std::string for runtime string -// formatting without compile time checks. +// Unlike ConstevalFormatString this supports RunTimeFormat-wrapped std::string +// for runtime string formatting without compile time checks. template struct FormatStringCheck { consteval FormatStringCheck(const char* str) : fmt{util::ConstevalFormatString{str}.fmt} {} - FormatStringCheck(const std::string& str) : fmt{str.c_str()} {} + FormatStringCheck(LIFETIMEBOUND const RuntimeFormat& run) : fmt{run.fmt.c_str()} {} FormatStringCheck(util::ConstevalFormatString str) : fmt{str.fmt} {} operator const char*() { return fmt; } const char* fmt; diff --git a/src/util/translation.h b/src/util/translation.h index 27747a16f2..cc29eef660 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -103,7 +103,7 @@ bilingual_str format(util::BilingualFmt fmt, const Args&... arg } }}; return bilingual_str{tfm::format(fmt.original, original_arg(args)...), - tfm::format(std::string{fmt.lit}, translated_arg(args)...)}; + tfm::format(RuntimeFormat{std::string{fmt.lit}}, translated_arg(args)...)}; } } // namespace tinyformat