From f860fc9310a995061b39f315de25319b89e3cc86 Mon Sep 17 00:00:00 2001 From: Justin Riddell Date: Sun, 19 May 2024 04:59:58 +0100 Subject: [PATCH] Check range_begin is dereferenceable Fixes issue #3839 An Eigen 3.4 2x2 matrix has a begin member function that returns void Be more strict checking that the result of calling *begin() is valid See input_or_output_iterator concept notes about void --- include/fmt/ranges.h | 12 ++++++------ test/ranges-test.cc | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 3a37c772a34bf..972048fda782d 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -68,7 +68,7 @@ template struct has_member_fn_begin_end_t : std::false_type {}; template -struct has_member_fn_begin_end_t().begin()), +struct has_member_fn_begin_end_t().begin()), decltype(std::declval().end())>> : std::true_type {}; @@ -99,15 +99,15 @@ struct has_mutable_begin_end : std::false_type {}; template struct has_const_begin_end< - T, - void_t< - decltype(detail::range_begin(std::declval&>())), - decltype(detail::range_end(std::declval&>()))>> + T, void_t&>())), + decltype(detail::range_end( + std::declval&>()))>> : std::true_type {}; template struct has_mutable_begin_end< - T, void_t())), + T, void_t())), decltype(detail::range_end(std::declval())), // the extra int here is because older versions of MSVC don't // SFINAE properly unless there are distinct types diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 4a69ad75e62f1..f166f187c040b 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -742,3 +742,21 @@ TEST(ranges_test, movable_only_istream_iter_join) { EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", fmt::join(std::move(first), last, ", "))); } + +namespace { +struct not_range { + void begin() const {} + void end() const {} +}; +} // namespace +FMT_BEGIN_NAMESPACE +template <> struct formatter : formatter { + auto format(const not_range&, format_context& ctx) const + -> format_context::iterator { + return formatter::format("Dummy output", ctx); + } +}; +FMT_END_NAMESPACE +TEST(ranges_test, format_not_range_using_specialized_formatter) { + EXPECT_EQ("Dummy output", fmt::format("{}", not_range{})); +}