abort with a descriptive message on bad HintFmt usage

Change-Id: Ic2f05572042343a8160fd971394372f5f2706fc4
This commit is contained in:
Qyriad 2024-04-10 19:25:30 -06:00
parent 80bbfe2034
commit 4e68deef80
2 changed files with 26 additions and 15 deletions

View file

@ -1,8 +1,15 @@
#pragma once #pragma once
///@file ///@file
#include <boost/format.hpp> #include <iostream>
#include <string> #include <string>
#include <optional>
#include <boost/format.hpp>
// Darwin stdenv does not define _GNU_SOURCE but does have _Unwind_Backtrace.
#ifdef __APPLE__
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
#endif
#include <boost/stacktrace.hpp>
#include "ansicolor.hh" #include "ansicolor.hh"
namespace nix { namespace nix {
@ -157,23 +164,27 @@ public:
*/ */
template<typename... Args> template<typename... Args>
HintFmt(const std::string & format, const Args &... args) 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) {} HintFmt(const HintFmt & hf) : fmt(hf.fmt) {}
template<typename... Args>
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 std::string str() const
{ {
return fmt.str(); return fmt.str();

View file

@ -15,9 +15,9 @@ TEST(HintFmt, arg_count)
ASSERT_EQ(HintFmt("%1%", "hello").str(), ANSI_MAGENTA "hello" ANSI_NORMAL); ASSERT_EQ(HintFmt("%1%", "hello").str(), ANSI_MAGENTA "hello" ANSI_NORMAL);
// Argument counts are detected at construction. // 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");
} }
} }