Skip to content

Commit fa3efb5

Browse files
author
MarcoFalke
committed
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.
1 parent fa6adb0 commit fa3efb5

File tree

5 files changed

+33
-20
lines changed

5 files changed

+33
-20
lines changed

src/test/fuzz/strprintf.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
#include <string>
1515
#include <vector>
1616

17+
template <typename... Args>
18+
void fuzz_fmt(const std::string& fmt, const Args&... args)
19+
{
20+
(void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
21+
}
22+
1723
FUZZ_TARGET(str_printf)
1824
{
1925
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
@@ -51,22 +57,22 @@ FUZZ_TARGET(str_printf)
5157
CallOneOf(
5258
fuzzed_data_provider,
5359
[&] {
54-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
60+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
5561
},
5662
[&] {
57-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
63+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
5864
},
5965
[&] {
60-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
66+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
6167
},
6268
[&] {
63-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
69+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
6470
},
6571
[&] {
66-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
72+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
6773
},
6874
[&] {
69-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
75+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeBool());
7076
});
7177
} catch (const tinyformat::format_error&) {
7278
}
@@ -91,28 +97,28 @@ FUZZ_TARGET(str_printf)
9197
CallOneOf(
9298
fuzzed_data_provider,
9399
[&] {
94-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
100+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
95101
},
96102
[&] {
97-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
103+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
98104
},
99105
[&] {
100-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
106+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
101107
},
102108
[&] {
103-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
109+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
104110
},
105111
[&] {
106-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
112+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
107113
},
108114
[&] {
109-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
115+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
110116
},
111117
[&] {
112-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
118+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
113119
},
114120
[&] {
115-
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
121+
fuzz_fmt(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
116122
});
117123
} catch (const tinyformat::format_error&) {
118124
}

src/test/fuzz/util/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct FuzzedWallet {
4646

4747
for (const std::string& desc_fmt : DESCS) {
4848
for (bool internal : {true, false}) {
49-
const auto descriptor{(strprintf)(desc_fmt, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})};
49+
const auto descriptor{strprintf(tfm::RuntimeFormat{desc_fmt}, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})};
5050

5151
FlatSigningProvider keys;
5252
std::string error;

src/test/util_string_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ template <unsigned NumArgs>
1616
void TfmFormatZeroes(const std::string& fmt)
1717
{
1818
std::apply([&](auto... args) {
19-
(void)tfm::format(fmt, args...);
19+
(void)tfm::format(tfm::RuntimeFormat{fmt}, args...);
2020
}, std::array<int, NumArgs>{});
2121
}
2222

src/tinyformat.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ namespace tfm = tinyformat;
142142
//------------------------------------------------------------------------------
143143
// Implementation details.
144144
#include <algorithm>
145+
#include <attributes.h> // Added for Bitcoin Core
145146
#include <iostream>
146147
#include <sstream>
147148
#include <stdexcept> // Added for Bitcoin Core
@@ -179,13 +180,19 @@ namespace tfm = tinyformat;
179180

180181
namespace tinyformat {
181182

183+
// Added for Bitcoin Core. Similar to std::runtime_format from C++26.
184+
struct RuntimeFormat {
185+
const std::string& fmt; // Not a string view, because tinyformat requires a c_str
186+
explicit RuntimeFormat(LIFETIMEBOUND const std::string& str) : fmt{str} {}
187+
};
188+
182189
// Added for Bitcoin Core. Wrapper for checking format strings at compile time.
183-
// Unlike ConstevalFormatString this supports std::string for runtime string
184-
// formatting without compile time checks.
190+
// Unlike ConstevalFormatString this supports RunTimeFormat-wrapped std::string
191+
// for runtime string formatting without compile time checks.
185192
template <unsigned num_params>
186193
struct FormatStringCheck {
187194
consteval FormatStringCheck(const char* str) : fmt{util::ConstevalFormatString<num_params>{str}.fmt} {}
188-
FormatStringCheck(const std::string& str) : fmt{str.c_str()} {}
195+
FormatStringCheck(LIFETIMEBOUND const RuntimeFormat& run) : fmt{run.fmt.c_str()} {}
189196
FormatStringCheck(util::ConstevalFormatString<num_params> str) : fmt{str.fmt} {}
190197
operator const char*() { return fmt; }
191198
const char* fmt;

src/util/translation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ bilingual_str format(util::BilingualFmt<sizeof...(Args)> fmt, const Args&... arg
103103
}
104104
}};
105105
return bilingual_str{tfm::format(fmt.original, original_arg(args)...),
106-
tfm::format(std::string{fmt.lit}, translated_arg(args)...)};
106+
tfm::format(RuntimeFormat{std::string{fmt.lit}}, translated_arg(args)...)};
107107
}
108108
} // namespace tinyformat
109109

0 commit comments

Comments
 (0)