diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh index c68591b72..aa7c6926a 100644 --- a/src/libutil/fmt.hh +++ b/src/libutil/fmt.hh @@ -1,8 +1,15 @@ #pragma once ///@file -#include +#include #include +#include +#include +// Darwin stdenv does not define _GNU_SOURCE but does have _Unwind_Backtrace. +#ifdef __APPLE__ +#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED +#endif +#include #include "ansicolor.hh" namespace nix { @@ -157,23 +164,27 @@ public: */ template HintFmt(const std::string & format, const Args &... args) - : HintFmt(boost::format(format), args...) + // Note the function try block. + try : fmt(fmt_internal::HintFmt(boost::format(format), args...).into_format()) { + if (this->fmt.remaining_args() != 0) { + // Abort. I don't want anything to catch this, I want a coredump. + std::cerr << "HintFmt received incorrect number of format args. Original format string: '"; + std::cerr << format << "'; number of arguments: " << sizeof...(args) << "\n"; + // And regardless of the coredump give me a damn stacktrace. + std::cerr << boost::stacktrace::stacktrace() << std::endl; + abort(); + } + } catch (boost::io::format_error & ex) { + // Same thing, but for anything that happens in the member initializers. + std::cerr << "HintFmt received incorrect format string. Original format string: '"; + std::cerr << format << "'; number of arguments: " << sizeof...(args) << "\n"; + std::cerr << boost::stacktrace::stacktrace() << std::endl; + abort(); } HintFmt(const HintFmt & hf) : fmt(hf.fmt) {} - template - HintFmt(boost::format && fmt, const Args &... args) - : fmt(fmt_internal::HintFmt(std::move(fmt), args...).into_format()) - { - if (this->fmt.remaining_args() != 0) { - throw boost::io::too_few_args( - this->fmt.bound_args() + this->fmt.fed_args(), this->fmt.expected_args() - ); - } - } - std::string str() const { return fmt.str(); diff --git a/tests/unit/libutil/fmt.cc b/tests/unit/libutil/fmt.cc index 383a688d3..90bcdfbe4 100644 --- a/tests/unit/libutil/fmt.cc +++ b/tests/unit/libutil/fmt.cc @@ -15,9 +15,9 @@ TEST(HintFmt, arg_count) ASSERT_EQ(HintFmt("%1%", "hello").str(), ANSI_MAGENTA "hello" ANSI_NORMAL); // Argument counts are detected at construction. - ASSERT_THROW(HintFmt("%s %s", 1), boost::io::too_few_args); + ASSERT_DEATH(HintFmt("%s %s", 1), "HintFmt received incorrect"); - ASSERT_THROW(HintFmt("%s", 1, 2), boost::io::too_many_args); + ASSERT_DEATH(HintFmt("%s", 1, 2), "HintFmt received incorrect"); } }