Make terminate cause a crash instead for the crashlog and stacktrace

This commit is contained in:
HJfod 2024-04-14 17:57:15 +03:00
parent 69bcab649e
commit 33e12646b8
2 changed files with 38 additions and 9 deletions
loader
include/Geode/utils
src/platform/windows

View file

@ -9,6 +9,22 @@ namespace geode {
}
namespace geode::utils {
#ifdef GEODE_IS_WINDOWS
static constexpr size_t GEODE_TERMINATE_EXCEPTION_CODE = 0x4000;
static constexpr size_t GEODE_UNREACHABLE_EXCEPTION_CODE = 0x4001;
static constexpr bool isGeodeExceptionCode(size_t code) {
return GEODE_TERMINATE_EXCEPTION_CODE <= code && code <= GEODE_UNREACHABLE_EXCEPTION_CODE;
}
#else
static constexpr size_t GEODE_TERMINATE_EXCEPTION_CODE = 0;
static constexpr size_t GEODE_UNREACHABLE_EXCEPTION_CODE = 0;
static constexpr bool isGeodeExceptionCode(size_t code) {
return false;
}
#endif
namespace detail {
// This needs to do stuff with `Mod*` which is not included in the file
GEODE_DLL std::string fmtTerminateError(const char* reason, Mod* mod, std::source_location loc);
@ -19,12 +35,11 @@ namespace geode::utils {
void terminate(
std::string const& reason,
Mod* mod = getMod(),
std::source_location loc = std::source_location::current()
std::source_location loc = std::source_location::current(),
size_t platformCode = GEODE_TERMINATE_EXCEPTION_CODE
) {
auto fullError = detail::fmtTerminateError(reason.c_str(), mod, loc);
// Add the error to the logfile
log::error("{}", fullError);
log::error("{}", detail::fmtTerminateError(reason.c_str(), mod, loc));
#ifdef GEODE_IS_WINDOWS
// If a debugger is attached, start debugging
@ -32,10 +47,14 @@ namespace geode::utils {
OutputDebugStringA(reason.c_str());
DebugBreak();
}
// Otherwise just terminate
// Otherwise terminate by raising an exception (which is caught by the crashlog handler)
else {
MessageBoxA(nullptr, "A Mod Crashed", fullError.c_str(), MB_ICONERROR);
std::terminate();
std::array<const void*, 2> errorList { static_cast<const void*>(reason.c_str()), mod };
RaiseException(
platformCode,
EXCEPTION_NONCONTINUABLE,
2, reinterpret_cast<ULONG_PTR*>(errorList.data())
);
}
#else
std::terminate();
@ -49,6 +68,6 @@ namespace geode::utils {
Mod* mod = getMod(),
std::source_location loc = std::source_location::current()
) {
return terminate(reason + " (Unreachable code path)", mod, loc);
terminate(reason, mod, loc, GEODE_UNREACHABLE_EXCEPTION_CODE);
}
}

View file

@ -9,6 +9,7 @@
#include <DbgHelp.h>
#include <Geode/utils/casts.hpp>
#include <Geode/utils/file.hpp>
#include <Geode/utils/terminate.hpp>
#include <Windows.h>
#include <chrono>
#include <ctime>
@ -66,6 +67,8 @@ static char const* getExceptionCodeString(DWORD code) {
EXP_STR(EXCEPTION_FLT_INVALID_OPERATION);
EXP_STR(EXCEPTION_FLT_OVERFLOW);
EXP_STR(EXCEPTION_INT_DIVIDE_BY_ZERO);
EXP_STR(GEODE_TERMINATE_EXCEPTION_CODE);
EXP_STR(GEODE_UNREACHABLE_EXCEPTION_CODE);
default: return "<Unknown>";
}
#undef EXP_STR
@ -267,7 +270,14 @@ static std::string getInfo(LPEXCEPTION_POINTERS info, Mod* faultyMod) {
}
stream << "Faulty Mod: " << (faultyMod ? faultyMod->getID() : "<Unknown>") << "\n";
} else {
}
else if (isGeodeExceptionCode(info->ExceptionRecord->ExceptionCode)) {
stream
<< "A mod has deliberately asked the game to crash.\n"
<< "Reason: " << reinterpret_cast<const char*>(info->ExceptionRecord->ExceptionInformation[0]) << "\n"
<< "Faulty Mod: " << reinterpret_cast<Mod*>(info->ExceptionRecord->ExceptionInformation[1])->getID() << "\n";
}
else {
stream << "Faulty Module: "
<< getModuleName(handleFromAddress(info->ExceptionRecord->ExceptionAddress), true)
<< "\n"