diff --git a/include/fmt/core.h b/include/fmt/core.h index c2920e16..2bda4aca 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -176,6 +176,13 @@ FMT_END_NAMESPACE_STD # define FMT_EXCEPTIONS 1 # endif #endif +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif // Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \ @@ -965,7 +972,12 @@ class iterator_buffer : public Traits, public buffer { : Traits(other), buffer(grow, data_, 0, buffer_size), out_(other.out_) {} - ~iterator_buffer() { flush(); } + ~iterator_buffer() { + FMT_TRY { flush(); } + FMT_CATCH(...) { + // Don't crash if flush fails during unwinding. + } + } auto out() -> OutputIt { flush(); diff --git a/include/fmt/format.h b/include/fmt/format.h index e5acae9c..2fdd18fb 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -137,14 +137,6 @@ FMT_END_NAMESPACE # endif #endif -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - #ifndef FMT_MAYBE_UNUSED # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) # define FMT_MAYBE_UNUSED [[maybe_unused]] diff --git a/test/core-test.cc b/test/core-test.cc index 3c811ce9..a19d0090 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -851,3 +851,26 @@ FMT_END_NAMESPACE TEST(core_test, trappy_conversion) { EXPECT_EQ(fmt::format("{}", its_a_trap()), "42"); } + +TEST(core_test, throw_in_buffer_dtor) { + enum { buffer_size = 256 }; + + struct throwing_iterator { + int& count; + + auto operator=(char) -> throwing_iterator& { + if (++count > buffer_size) throw std::exception(); + return *this; + } + auto operator*() -> throwing_iterator& { return *this; } + auto operator++() -> throwing_iterator& { return *this; } + auto operator++(int) -> throwing_iterator { return *this; } + }; + + try { + int count = 0; + fmt::format_to(throwing_iterator{count}, fmt::runtime("{:{}}{"), "", + buffer_size + 1); + } catch (const std::exception&) { + } +}