diff --git a/src/libutil/error.cc b/src/libutil/error.cc index b1858911a..ccd008c7c 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -1,3 +1,5 @@ +#include + #include "error.hh" #include "environment-variables.hh" #include "signals.hh" @@ -430,16 +432,36 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s return out; } +/** Write to stderr in a robust and minimal way, considering that the process + * may be in a bad state. + */ +static void writeErr(std::string_view buf) +{ + while (!buf.empty()) { + auto n = write(STDERR_FILENO, buf.data(), buf.size()); + if (n < 0) { + if (errno == EINTR) continue; + abort(); + } + buf = buf.substr(n); + } +} + void panic(std::string_view msg) { - printError(msg); - printError("This was a fatal error, aborting."); + writeErr("\n\n" ANSI_RED "terminating due to unexpected unrecoverable internal error: " ANSI_NORMAL ); + writeErr(msg); + writeErr("\n"); abort(); } void panic(const char * file, int line, const char * func) { - panic(std::string("Unexpected condition in ") + func + " at " + file + ":" + std::to_string(line)); + char buf[512]; + int n = snprintf(buf, sizeof(buf), "Unexpected condition in %s at %s:%d", func, file, line); + if (n < 0) + panic("Unexpected condition and could not format error message"); + panic(std::string_view(buf, std::min(static_cast(sizeof(buf)), n))); } } diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 572a1baf7..58d902622 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -275,17 +275,13 @@ void throwExceptionSelfCheck(); /** * Print a message and abort(). - * - * @note: This assumes that the logger is operational */ [[noreturn]] void panic(std::string_view msg); /** * Print a basic error message with source position and abort(). - * Use the unreachable macro to call this. - * - * @note: This assumes that the logger is operational + * Use the unreachable() macro to call this. */ [[noreturn]] void panic(const char * file, int line, const char * func); @@ -295,6 +291,6 @@ void panic(const char * file, int line, const char * func); * * @note: This assumes that the logger is operational */ -#define unreachable() (panic(__FILE__, __LINE__, __func__)) +#define unreachable() (::nix::panic(__FILE__, __LINE__, __func__)) }