diff --git a/include/fmt/base.h b/include/fmt/base.h index c94b8c6d..2ba23d5a 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2778,6 +2778,11 @@ void check_format_string(S format_str) { 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 // a GCC <= 4.8 bug. template struct vformat_args { @@ -2957,9 +2962,16 @@ struct format_to_result { /// Specifies if the output was truncated. bool truncated; - FMT_CONSTEXPR operator OutputIt&() & noexcept { return out; } - FMT_CONSTEXPR operator const OutputIt&() const& noexcept { return out; } - FMT_CONSTEXPR operator OutputIt&&() && noexcept { + FMT_CONSTEXPR operator OutputIt&() & { + detail::report_truncation(truncated); + 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(out); } }; diff --git a/test/base-test.cc b/test/base-test.cc index 18a15e82..dcacaab0 100644 --- a/test/base-test.cc +++ b/test/base-test.cc @@ -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").precision == 42, ""); static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, ""); - static_assert( - parse_test_specs("f").type == fmt::presentation_type::fixed, ""); + static_assert(parse_test_specs("f").type == fmt::presentation_type::fixed, + ""); } struct test_format_string_handler { @@ -706,7 +706,7 @@ TEST(core_test, format_to) { EXPECT_EQ(s, "42"); } -TEST(core_test, format_to_c_array) { +TEST(core_test, format_to_array) { char buffer[4]; auto result = fmt::format_to(buffer, "{}", 12345); 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("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"); EXPECT_EQ(4, std::distance(&buffer[0], result.out)); EXPECT_TRUE(result.truncated);