Skip to content

Commit

Permalink
Add fail_fast runtime error policy
Browse files Browse the repository at this point in the history
This adds a new fail_fast runtime error policy to go with our existing terminate and unwind policies.

As the name suggests, fail_fast is intended to tear down the process in the fastest way possible should a runtime error occur. It uses `__builtin_trap()` on GCC and Clang, the `__fastfail()` intrinsic on MSVC, and otherwise falls back to `std::abort()`. Unlike the terminate policy, it never attempts to print a message to stderr.
  • Loading branch information
tcbrindle committed Sep 9, 2024
1 parent 291df6d commit 0b6810a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
61 changes: 49 additions & 12 deletions include/flux/core/assert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
#include <stdexcept>
#include <type_traits>

#if defined(__has_builtin)
# if __has_builtin(__builtin_trap)
# define FLUX_HAS_BUILTIN_TRAP 1
# endif
#elif defined(_MSC_VER)
# include <intrin.h>
# define FLUX_HAS_FASTFAIL 1
#endif

namespace flux {

FLUX_EXPORT
Expand All @@ -24,21 +33,49 @@ struct unrecoverable_error : std::logic_error {
namespace detail {

struct runtime_error_fn {
private:
[[noreturn]]
void operator()(char const* msg,
std::source_location loc = std::source_location::current()) const
static inline void fail_fast()
{
if constexpr (config::on_error == error_policy::unwind) {
char buf[1024];
std::snprintf(buf, 1024, "%s:%u: Fatal error: %s",
loc.file_name(), loc.line(), msg);
throw unrecoverable_error(buf);
#if FLUX_HAS_BUILTIN_TRAP
__builtin_trap();
#elif FLUX_HAS_FASTFAIL
__fastfail(7); // FAST_FAIL_FATAL_APP_EXIT
#else
std::abort();
#endif
}

[[noreturn]]
static void unwind(const char* msg, std::source_location loc)
{
char buf[1024];
std::snprintf(buf, 1024, "%s:%u: Fatal error: %s",
loc.file_name(), loc.line(), msg);
throw unrecoverable_error(buf);
}

[[noreturn]]
static void terminate(const char* msg, std::source_location loc)
{
if constexpr (config::print_error_on_terminate) {
std::fprintf(stderr, "%s:%u: Fatal error: %s\n",
loc.file_name(), loc.line(), msg);
}
std::terminate();
}

public:
[[noreturn]]
inline void operator()(char const* msg,
std::source_location loc = std::source_location::current()) const
{
if constexpr (config::on_error == error_policy::fail_fast) {
fail_fast();
} else if constexpr (config::on_error == error_policy::unwind) {
unwind(msg, loc);
} else {
if constexpr (config::print_error_on_terminate) {
std::fprintf(stderr, "%s:%u: Fatal error: %s\n",
loc.file_name(), loc.line(), msg);
}
std::terminate();
terminate(msg, loc);
}
}
};
Expand Down
8 changes: 6 additions & 2 deletions include/flux/core/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
#include <type_traits>

#define FLUX_ERROR_POLICY_TERMINATE 1
#define FLUX_ERROR_POLICY_UNWIND 2
#define FLUX_ERROR_POLICY_UNWIND 2
#define FLUX_ERROR_POLICY_FAIL_FAST 3

#define FLUX_OVERFLOW_POLICY_ERROR 10
#define FLUX_OVERFLOW_POLICY_WRAP 11
Expand Down Expand Up @@ -47,6 +48,8 @@
# define FLUX_ERROR_POLICY FLUX_ERROR_POLICY_TERMINATE
#elif defined(FLUX_UNWIND_ON_ERROR)
# define FLUX_ERROR_POLICY FLUX_ERROR_POLICY_UNWIND
#elif defined(FLUX_FAIL_FAST_ON_ERROR)
# define FLUX_ERROR_POLICY FLUX_ERROR_POLICY_FAIL_FAST
#else
# define FLUX_ERROR_POLICY FLUX_DEFAULT_ERROR_POLICY
#endif // FLUX_TERMINATE_ON_ERROR
Expand Down Expand Up @@ -123,7 +126,8 @@ namespace flux {
FLUX_EXPORT
enum class error_policy {
terminate = FLUX_ERROR_POLICY_TERMINATE,
unwind = FLUX_ERROR_POLICY_UNWIND
unwind = FLUX_ERROR_POLICY_UNWIND,
fail_fast = FLUX_ERROR_POLICY_FAIL_FAST
};

FLUX_EXPORT
Expand Down

0 comments on commit 0b6810a

Please sign in to comment.