Make panic() and unreachable() robust

Plus one or two tweaks.
This commit is contained in:
Robert Hensing 2024-07-24 17:53:17 +02:00
parent 3172e88af5
commit 55a654abfd
2 changed files with 27 additions and 9 deletions

View file

@ -1,3 +1,5 @@
#include <algorithm>
#include "error.hh" #include "error.hh"
#include "environment-variables.hh" #include "environment-variables.hh"
#include "signals.hh" #include "signals.hh"
@ -430,16 +432,36 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
return out; 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) void panic(std::string_view msg)
{ {
printError(msg); writeErr("\n\n" ANSI_RED "terminating due to unexpected unrecoverable internal error: " ANSI_NORMAL );
printError("This was a fatal error, aborting."); writeErr(msg);
writeErr("\n");
abort(); abort();
} }
void panic(const char * file, int line, const char * func) 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<int>(sizeof(buf)), n)));
} }
} }

View file

@ -275,17 +275,13 @@ void throwExceptionSelfCheck();
/** /**
* Print a message and abort(). * Print a message and abort().
*
* @note: This assumes that the logger is operational
*/ */
[[noreturn]] [[noreturn]]
void panic(std::string_view msg); void panic(std::string_view msg);
/** /**
* Print a basic error message with source position and abort(). * Print a basic error message with source position and abort().
* Use the unreachable macro to call this. * Use the unreachable() macro to call this.
*
* @note: This assumes that the logger is operational
*/ */
[[noreturn]] [[noreturn]]
void panic(const char * file, int line, const char * func); 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 * @note: This assumes that the logger is operational
*/ */
#define unreachable() (panic(__FILE__, __LINE__, __func__)) #define unreachable() (::nix::panic(__FILE__, __LINE__, __func__))
} }