AK: Print a more useful error message when a MUST(...) fails

```
VERIFICATION FAILED: !_temporary_result.is_error()
```

is not really a helpful error message.

When we are including `AK/Format.h`, which is most of the time,
we can easily print a much more useful error message:

```
UNEXPECTED ERROR: Cannot allocate memory (errno=12)
```
This commit is contained in:
Jonne Ransijn 2024-11-30 16:29:25 +01:00 committed by Andreas Kling
parent 0afd7f166a
commit e38b206957
Notes: github-actions[bot] 2024-12-02 19:08:30 +00:00
4 changed files with 41 additions and 23 deletions

View file

@ -81,45 +81,42 @@ ALWAYS_INLINE void dump_backtrace()
extern "C" {
void ak_verification_failed(char const* message)
bool ak_colorize_output(void)
{
#if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID)
bool colorize_output = true;
return true;
#elif defined(AK_OS_WINDOWS)
bool colorize_output = false;
return false;
#else
bool colorize_output = isatty(STDERR_FILENO) == 1;
return isatty(STDERR_FILENO) == 1;
#endif
}
if (colorize_output)
void ak_trap(void)
{
#if defined(AK_HAS_BACKTRACE_HEADER)
dump_backtrace();
#endif
__builtin_trap();
}
void ak_verification_failed(char const* message)
{
if (ak_colorize_output())
ERRORLN("\033[31;1mVERIFICATION FAILED\033[0m: {}", message);
else
ERRORLN("VERIFICATION FAILED: {}", message);
#if defined(AK_HAS_BACKTRACE_HEADER)
dump_backtrace();
#endif
__builtin_trap();
ak_trap();
}
void ak_assertion_failed(char const* message)
{
#if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID)
bool colorize_output = true;
#elif defined(AK_OS_WINDOWS)
bool colorize_output = false;
#else
bool colorize_output = isatty(STDERR_FILENO) == 1;
#endif
if (colorize_output)
if (ak_colorize_output())
ERRORLN("\033[31;1mASSERTION FAILED\033[0m: {}", message);
else
ERRORLN("ASSERTION FAILED: {}", message);
#if defined(AK_HAS_BACKTRACE_HEADER)
dump_backtrace();
#endif
__builtin_trap();
ak_trap();
}
}

View file

@ -6,6 +6,9 @@
#pragma once
extern "C" bool ak_colorize_output(void);
extern "C" __attribute__((noreturn)) void ak_trap(void);
extern "C" __attribute__((noreturn)) void ak_verification_failed(char const*);
#define __stringify_helper(x) #x
#define __stringify(x) __stringify_helper(x)

View file

@ -775,6 +775,21 @@ struct Formatter<Optional<T>> : Formatter<FormatString> {
} // namespace AK
#undef AK_HANDLE_UNEXPECTED_ERROR
#define AK_HANDLE_UNEXPECTED_ERROR(result) \
if (result.is_error()) [[unlikely]] { \
if (ak_colorize_output()) { \
::AK::warn("\033[31;1mUNEXPECTED ERROR\033[0m"); \
} else { \
::AK::warn("UNEXPECTED ERROR"); \
} \
if constexpr (::AK::HasFormatter<decltype(result.release_error())>) { \
::AK::warn(": {}", result.release_error()); \
} \
::AK::warnln(" at {}:{}", __FILE__, __LINE__); \
ak_trap(); \
}
#if USING_AK_GLOBALLY
using AK::out;
using AK::outln;

View file

@ -9,6 +9,9 @@
#include <AK/Diagnostics.h>
#include <AK/StdLibExtras.h>
// This macro is redefined in `AK/Format.h` to give a nicer error message.
#define AK_HANDLE_UNEXPECTED_ERROR(result) VERIFY(!result.is_error());
// NOTE: This macro works with any result type that has the expected APIs.
// It's designed with AK::Result and AK::Error in mind.
//
@ -40,6 +43,6 @@
auto&& _temporary_result = (expression)); \
static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_result.release_value())>, \
"Do not return a reference from a fallible expression"); \
VERIFY(!_temporary_result.is_error()); \
AK_HANDLE_UNEXPECTED_ERROR(_temporary_result) \
_temporary_result.release_value(); \
})