Files
lix/lix/libmain/crash-handler.cc
T
Maximilian Bosch e23bed5e64 libutil: expose the functionality of Lix's exception handler
This introduces three new things:

* `handleException` which prints out exception details and its stack
  trace.
* `handleExceptionWithAsyncTrace` which does the same, but also prints
  the async trace if any.
* `LIX_BLOCK_ON` which is awaits a promise and adds an exception trace
  if an exception got thrown, similar to `LIX_TRY_AWAIT`. However, this
  is not supposed to be used in async functions, but on callsites of
  `aio.blockOn()` which is especially useful for Hydra[1].

For `LIX_BLOCK_ON` I had to introduce another function because there's
apparently no way to implement all of it in a macro: on macros with
compound statements the return value must be a trivial expression at the
bottom, i.e. no `try`/`catch`. Now, returning the value from the
`try`-block requires the variable to be defined up-front, but for that
we'd need to know the type-name. Hence the construction with a
template-function being invoked by a macro that injects the current
source-location.

[1] https://git.lix.systems/lix-project/hydra/pulls/52

Change-Id: I56cc92c94f7e8f0be5d4dc5a7d8cb21a92e776ef
2025-06-20 18:14:38 +02:00

45 lines
1.3 KiB
C++

#include "lix/libmain/crash-handler.hh"
#include "lix/libutil/error.hh"
#include "lix/libutil/logging.hh"
#include <boost/core/demangle.hpp>
#include <exception>
namespace nix {
namespace {
void onTerminate()
{
std::shared_ptr<const std::list<BaseException::AsyncTraceFrame>> asyncTrace;
logFatal("Lix crashed. This is a bug. We would appreciate if you report it along with what caused it at https://git.lix.systems/lix-project/lix/issues with the following information included:\n");
try {
std::exception_ptr eptr = std::current_exception();
if (eptr) {
std::rethrow_exception(eptr);
} else {
logFatal("std::terminate() called without exception");
}
} catch (const BaseException & ex) {
logException("Exception", ex);
} catch (const std::exception & ex) { // NOLINT(lix-foreign-exceptions)
logException("Exception", ex);
} catch (...) {
logFatal("Unknown exception! Spooky.");
}
std::abort();
}
}
void registerCrashHandler()
{
// DO NOT use this for signals. Boost stacktrace is very much not
// async-signal-safe, and in a world with ASLR, addr2line is pointless.
//
// If you want signals, set up a minidump system and do it out-of-process.
std::set_terminate(onTerminate);
}
}