Prevent silent data loss

This commit is contained in:
Victor Zverovich
2024-06-22 07:16:43 -07:00
parent 2c0d9e9409
commit b1efe8516e
2 changed files with 22 additions and 6 deletions

View File

@@ -2778,6 +2778,11 @@ void check_format_string(S format_str) {
ignore_unused(error); ignore_unused(error);
} }
// Report truncation to prevent silent data loss.
inline void report_truncation(bool truncated) {
if (truncated) report_error("output is truncated");
}
// Use vformat_args and avoid type_identity to keep symbols short and workaround // Use vformat_args and avoid type_identity to keep symbols short and workaround
// a GCC <= 4.8 bug. // a GCC <= 4.8 bug.
template <typename Char = char> struct vformat_args { template <typename Char = char> struct vformat_args {
@@ -2957,9 +2962,16 @@ struct format_to_result {
/// Specifies if the output was truncated. /// Specifies if the output was truncated.
bool truncated; bool truncated;
FMT_CONSTEXPR operator OutputIt&() & noexcept { return out; } FMT_CONSTEXPR operator OutputIt&() & {
FMT_CONSTEXPR operator const OutputIt&() const& noexcept { return out; } detail::report_truncation(truncated);
FMT_CONSTEXPR operator OutputIt&&() && noexcept { return out;
}
FMT_CONSTEXPR operator const OutputIt&() const& {
detail::report_truncation(truncated);
return out;
}
FMT_CONSTEXPR operator OutputIt&&() && {
detail::report_truncation(truncated);
return static_cast<OutputIt&&>(out); return static_cast<OutputIt&&>(out);
} }
}; };

View File

@@ -516,8 +516,8 @@ TEST(core_test, constexpr_parse_format_specs) {
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, ""); static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
static_assert(parse_test_specs(".42").precision == 42, ""); static_assert(parse_test_specs(".42").precision == 42, "");
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, ""); static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
static_assert( static_assert(parse_test_specs("f").type == fmt::presentation_type::fixed,
parse_test_specs("f").type == fmt::presentation_type::fixed, ""); "");
} }
struct test_format_string_handler { struct test_format_string_handler {
@@ -706,7 +706,7 @@ TEST(core_test, format_to) {
EXPECT_EQ(s, "42"); EXPECT_EQ(s, "42");
} }
TEST(core_test, format_to_c_array) { TEST(core_test, format_to_array) {
char buffer[4]; char buffer[4];
auto result = fmt::format_to(buffer, "{}", 12345); auto result = fmt::format_to(buffer, "{}", 12345);
EXPECT_EQ(4, std::distance(&buffer[0], result.out)); EXPECT_EQ(4, std::distance(&buffer[0], result.out));
@@ -714,6 +714,10 @@ TEST(core_test, format_to_c_array) {
EXPECT_EQ(buffer + 4, result.out); EXPECT_EQ(buffer + 4, result.out);
EXPECT_EQ("1234", fmt::string_view(buffer, 4)); EXPECT_EQ("1234", fmt::string_view(buffer, 4));
char* out = nullptr;
EXPECT_THROW(out = result, std::runtime_error);
(void)out;
result = fmt::format_to(buffer, "{:s}", "foobar"); result = fmt::format_to(buffer, "{:s}", "foobar");
EXPECT_EQ(4, std::distance(&buffer[0], result.out)); EXPECT_EQ(4, std::distance(&buffer[0], result.out));
EXPECT_TRUE(result.truncated); EXPECT_TRUE(result.truncated);