Add cpptrace in I_Error on windows, minidumps, stricter warnings, optimized drawers in debug

This commit is contained in:
Eidolon 2025-09-21 14:08:15 -05:00
parent c1b22c0c73
commit 94ef03dcd2
11 changed files with 294 additions and 99 deletions

View file

@ -125,6 +125,9 @@ find_package(PNG REQUIRED)
find_package(SDL2 CONFIG REQUIRED) find_package(SDL2 CONFIG REQUIRED)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
find_package(Opus REQUIRED) find_package(Opus REQUIRED)
if(WIN32 AND NOT MINGW)
find_package(cpptrace CONFIG REQUIRED)
endif()
# Use the one in thirdparty/fmt to guarantee a minimum version # Use the one in thirdparty/fmt to guarantee a minimum version
#find_package(FMT CONFIG REQUIRED) #find_package(FMT CONFIG REQUIRED)

View file

@ -54,8 +54,8 @@
"name": "__develop-cl", "name": "__develop-cl",
"hidden": true, "hidden": true,
"cacheVariables": { "cacheVariables": {
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG", "CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG", "CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"SRB2_CONFIG_DEV_BUILD": "ON", "SRB2_CONFIG_DEV_BUILD": "ON",
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }
@ -64,8 +64,8 @@
"name": "__release-cl", "name": "__release-cl",
"hidden": true, "hidden": true,
"cacheVariables": { "cacheVariables": {
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG", "CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG", "CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"SRB2_CONFIG_DEV_BUILD": "OFF", "SRB2_CONFIG_DEV_BUILD": "OFF",
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }

View file

@ -176,6 +176,41 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
p_deepcopy.cpp p_deepcopy.cpp
) )
# Always compile some files with optimizations in Debug config.
# This is to make the debugging experience less slow for the majority of cases.
set(always_optimize_options "")
if(MSVC)
set(always_optimize_options "$<$<CONFIG:Debug>:/O2;/Ob2>")
else()
set(always_optimize_options "$<$<CONFIG:Debug>:-O3>")
endif()
set_source_files_properties(
r_bsp.cpp
r_data.c
r_debug.cpp
r_debug_parser.cpp
r_debug_printer.cpp
r_draw.cpp
r_fps.cpp
r_main.cpp
r_plane.cpp
r_segs.cpp
r_skins.c
r_sky.c
r_splats.c
r_spritefx.cpp
r_things.cpp
r_bbox.c
r_textures.cpp
r_textures_dups.cpp
r_patch.cpp
r_patchrotation.c
r_picformats.c
r_portal.c
PROPERTIES
COMPILE_OPTIONS "${always_optimize_options}"
)
set_target_properties(SRB2SDL2 PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/sdl/macosx/MacOSXBundleInfo.plist.in") set_target_properties(SRB2SDL2 PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/sdl/macosx/MacOSXBundleInfo.plist.in")
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES) if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
@ -210,7 +245,7 @@ add_custom_target(_SRB2_reconf ALL
) )
add_dependencies(SRB2SDL2 _SRB2_reconf) add_dependencies(SRB2SDL2 _SRB2_reconf)
if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows") if(("${CMAKE_COMPILER_IS_GNUCC}") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase") target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
if("${SRB2_CONFIG_STATIC_STDLIB}") if("${SRB2_CONFIG_STATIC_STDLIB}")
# On MinGW with internal libraries, link the standard library statically # On MinGW with internal libraries, link the standard library statically
@ -224,8 +259,19 @@ if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND
endif() endif()
endif() endif()
if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link.exe") if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link\\.exe")
target_link_options(SRB2SDL2 PRIVATE /MANIFEST:NO) target_link_options(SRB2SDL2 PRIVATE /MANIFEST:NO)
target_link_libraries(SRB2SDL2 PRIVATE "dbghelp")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
# Stuff to make paths not include the builder's file system paths on clang-cl
string(REPLACE "/" "\\" backslashes_cmake_source_dir "${CMAKE_SOURCE_DIR}")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=X:/ringracers>")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${backslashes_cmake_source_dir}=X:/ringracers>")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-compilation-dir=${CMAKE_SOURCE_DIR}>")
target_link_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/pdbaltpath:%_PDB%>")
endif() endif()
target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17) target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
@ -283,6 +329,10 @@ target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG) target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl) target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
target_link_libraries(SRB2SDL2 PRIVATE Opus::opus) target_link_libraries(SRB2SDL2 PRIVATE Opus::opus)
if(WIN32 AND NOT MINGW)
target_link_libraries(SRB2SDL2 PRIVATE cpptrace::cpptrace)
target_compile_definitions(SRB2SDL2 PRIVATE HAVE_CPPTRACE)
endif()
target_link_libraries(SRB2SDL2 PRIVATE ReNameNoise::renamenoise) target_link_libraries(SRB2SDL2 PRIVATE ReNameNoise::renamenoise)
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
target_link_libraries(SRB2SDL2 PRIVATE -lexecinfo) target_link_libraries(SRB2SDL2 PRIVATE -lexecinfo)
@ -461,6 +511,7 @@ target_compile_options(SRB2SDL2 PRIVATE
# This is a direct translation from versions.mk # This is a direct translation from versions.mk
$<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>: $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
-Wall -Wall
-Werror-implicit-function-declaration
-Wno-trigraphs -Wno-trigraphs
-W # Was controlled by RELAXWARNINGS -W # Was controlled by RELAXWARNINGS
-pedantic -pedantic
@ -545,6 +596,7 @@ target_compile_options(SRB2SDL2 PRIVATE
$<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>: $<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
#-Wall #-Wall
-Werror=microsoft -Werror=microsoft
-Werror=implicit-function-declaration
-Wreturn-type # Missing returns in non-void function -Wreturn-type # Missing returns in non-void function
-Wduplicate-decl-specifier -Wduplicate-decl-specifier
-Wsometimes-uninitialized -Wsometimes-uninitialized
@ -570,9 +622,14 @@ target_compile_options(SRB2SDL2 PRIVATE
# C++, GNU # C++, GNU
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:GNU>>: $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:GNU>>:
-Wall -Wall
-Wno-c++98-compat
-Wno-c++11-compat
-Wno-c++14-compat # No C++14 compat needed
-Werror=c++20-extensions
-Werror=c++23-extensions # Disallow newer language features entirely
> >
# C++, GNU, Clang and Apple Clang # C++, Clang and Apple Clang
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>>: $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>>:
#-Wall #-Wall
-Werror=microsoft -Werror=microsoft
@ -584,6 +641,8 @@ target_compile_options(SRB2SDL2 PRIVATE
-Wno-c++98-compat -Wno-c++98-compat
-Wno-c++11-compat -Wno-c++11-compat
-Wno-c++14-compat # No C++14 compat needed -Wno-c++14-compat # No C++14 compat needed
-Werror=c++20-extensions
-Werror=c++23-extensions # Disallow newer language features entirely
-Wno-unused-but-set-variable # Setting unread variables is fine (nontrivial C++ types issue) -Wno-unused-but-set-variable # Setting unread variables is fine (nontrivial C++ types issue)
-Wno-misleading-indentation # Some cases in code currently -Wno-misleading-indentation # Some cases in code currently
-Wno-deprecated-non-prototype # We have no intention of using C23 yet. -Wno-deprecated-non-prototype # We have no intention of using C23 yet.
@ -594,6 +653,8 @@ target_compile_options(SRB2SDL2 PRIVATE
-Wno-unused-function -Wno-unused-function
> >
# C++, Clang and Apple Clang
# C++, MSVC # C++, MSVC
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>: $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:
/Wv:19.20.27004.0 /Wv:19.20.27004.0

View file

@ -457,7 +457,7 @@ enum {
*/ */
void I_Error(const char *error, ...) FUNCIERROR; FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...);
/** \brief write a message to stderr (use before I_Quit) for when you need to quit with a msg, but need /** \brief write a message to stderr (use before I_Quit) for when you need to quit with a msg, but need
the return code 0 of I_Quit(); the return code 0 of I_Quit();

View file

@ -92,7 +92,7 @@ void I_OsPolling(void);
/** \brief Called by M_Responder when quit is selected, return exit code 0 /** \brief Called by M_Responder when quit is selected, return exit code 0
*/ */
void I_Quit(void) FUNCNORETURN; FUNCNORETURN void ATTRNORETURN I_Quit(void);
typedef enum typedef enum
{ {

View file

@ -29,7 +29,7 @@ menuitem_t OPTIONS_Voice[] =
NULL, srb2::itemaction(&cv_voice_inputamp), 0, 0}, NULL, srb2::itemaction(&cv_voice_inputamp), 0, 0},
{IT_STRING | IT_CVAR, "Input Noise Suppression", "Suppress background noise from your voice.", {IT_STRING | IT_CVAR, "Input Noise Suppression", "Suppress background noise from your voice.",
NULL, {.cvar = &cv_voice_denoise}, 0, 0}, NULL, srb2::itemaction(&cv_voice_denoise), 0, 0},
{IT_STRING | IT_CVAR, "Input Sensitivity", "Voice higher than this threshold will transmit, in decibels.", {IT_STRING | IT_CVAR, "Input Sensitivity", "Voice higher than this threshold will transmit, in decibels.",
NULL, srb2::itemaction(&cv_voice_activationthreshold), 0, 0 }, NULL, srb2::itemaction(&cv_voice_activationthreshold), 0, 0 },

View file

@ -11,6 +11,7 @@
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomstat.h" #include "../doomstat.h"
#include "../info.h" #include "../info.h"
#include "../g_game.h"
#include "../k_objects.h" #include "../k_objects.h"
#include "../p_local.h" #include "../p_local.h"
#include "../r_state.h" #include "../r_state.h"

View file

@ -732,8 +732,7 @@ void R_RenderMaskedSegRange(drawseg_t *drawseg, INT32 x1, INT32 x2)
template <typename T> template <typename T>
static constexpr T saturating_add(T x, T y) noexcept static constexpr T saturating_add(T x, T y) noexcept
{ {
INT64 z; INT64 z = static_cast<INT64>(x) + static_cast<INT64>(y);
z = static_cast<INT64>(x) + static_cast<INT64>(y);
if (z > static_cast<INT64>(std::numeric_limits<T>::max())) if (z > static_cast<INT64>(std::numeric_limits<T>::max()))
{ {
z = static_cast<INT64>(std::numeric_limits<T>::max()); z = static_cast<INT64>(std::numeric_limits<T>::max());
@ -748,8 +747,7 @@ static constexpr T saturating_add(T x, T y) noexcept
template <typename T> template <typename T>
static constexpr T saturating_mul(T x, T y) noexcept static constexpr T saturating_mul(T x, T y) noexcept
{ {
INT64 z; INT64 z = static_cast<INT64>(x) * static_cast<INT64>(y);
z = static_cast<INT64>(x) * static_cast<INT64>(y);
if (z > static_cast<INT64>(std::numeric_limits<T>::max())) if (z > static_cast<INT64>(std::numeric_limits<T>::max()))
{ {
z = static_cast<INT64>(std::numeric_limits<T>::max()); z = static_cast<INT64>(std::numeric_limits<T>::max());

View file

@ -20,7 +20,6 @@
#include "../core/string.h" #include "../core/string.h"
#include <exception> #include <exception>
#include <stdexcept>
#include <tracy/tracy/Tracy.hpp> #include <tracy/tracy/Tracy.hpp>
@ -32,11 +31,7 @@
#include <errno.h> #include <errno.h>
#endif #endif
extern "C" {
#include "time.h" // For log timestamps #include "time.h" // For log timestamps
}
#ifdef HAVE_SDL
#ifdef HAVE_TTF #ifdef HAVE_TTF
#include "SDL.h" #include "SDL.h"
@ -68,46 +63,6 @@ char logfilename[1024];
#endif #endif
#endif #endif
#if defined (_WIN32)
extern "C" {
#include "../win32/win_dbg.h"
}
typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID);
#endif
#if defined (_WIN32)
static inline VOID MakeCodeWritable(VOID)
{
#ifdef USEASM // Disable write-protection of code segment
DWORD OldRights;
const DWORD NewRights = PAGE_EXECUTE_READWRITE;
PBYTE pBaseOfImage = (PBYTE)GetModuleHandle(NULL);
PIMAGE_DOS_HEADER dosH =(PIMAGE_DOS_HEADER)pBaseOfImage;
PIMAGE_NT_HEADERS ntH = (PIMAGE_NT_HEADERS)(pBaseOfImage + dosH->e_lfanew);
PIMAGE_OPTIONAL_HEADER oH = (PIMAGE_OPTIONAL_HEADER)
((PBYTE)ntH + sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER));
LPVOID pA = pBaseOfImage+oH->BaseOfCode;
SIZE_T pS = oH->SizeOfCode;
#if 1 // try to find the text section
PIMAGE_SECTION_HEADER ntS = IMAGE_FIRST_SECTION (ntH);
WORD s;
for (s = 0; s < ntH->FileHeader.NumberOfSections; s++)
{
if (memcmp (ntS[s].Name, ".text\0\0", 8) == 0)
{
pA = pBaseOfImage+ntS[s].VirtualAddress;
pS = ntS[s].Misc.VirtualSize;
break;
}
}
#endif
if (!VirtualProtect(pA,pS,NewRights,&OldRights))
I_Error("Could not make code writable\n");
#endif
}
#endif
#ifdef LOGMESSAGES #ifdef LOGMESSAGES
static void InitLogging(void) static void InitLogging(void)
{ {
@ -212,10 +167,6 @@ static void init_exchndl()
if (pfnExcHndlInit != NULL) if (pfnExcHndlInit != NULL)
(pfnExcHndlInit)(); (pfnExcHndlInit)();
} }
#else
static void init_exchndl()
{
}
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@ -300,25 +251,12 @@ int main(int argc, char **argv)
//I_OutputMsg("I_StartupSystem() ...\n"); //I_OutputMsg("I_StartupSystem() ...\n");
I_StartupSystem(); I_StartupSystem();
#if defined (_WIN32)
#if defined (_WIN32) && !defined(_MSC_VER)
if (!M_CheckParm("-noexchndl")) if (!M_CheckParm("-noexchndl"))
{
#if 0 // just load the DLL
p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsDebuggerPresent");
if ((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent())
#ifdef BUGTRAP
&& !InitBugTrap()
#endif
)
#endif
{ {
init_exchndl(); init_exchndl();
} }
}
#ifndef __MINGW32__
prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo);
#endif
MakeCodeWritable();
#endif #endif
try { try {
@ -353,8 +291,6 @@ int main(int argc, char **argv)
return 0; return 0;
} }
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
int WINAPI WinMain(HINSTANCE pInstance, HINSTANCE pPrevInstance, LPSTR lpCmdLine, int nShowCmd) int WINAPI WinMain(HINSTANCE pInstance, HINSTANCE pPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{ {

View file

@ -39,6 +39,12 @@ typedef DWORD (WINAPI *p_timeGetTime) (void);
typedef UINT (WINAPI *p_timeEndPeriod) (UINT); typedef UINT (WINAPI *p_timeEndPeriod) (UINT);
typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR); typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR);
typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#if defined(_WIN32) && !defined(__GNUC__)
#define USE_DBGHELP
#include <DbgHelp.h>
#endif
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -141,6 +147,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#define UNIXBACKTRACE #define UNIXBACKTRACE
#endif #endif
#ifdef HAVE_CPPTRACE
#include <cpptrace/cpptrace.hpp>
#endif
// Locations for searching for bios.pk3 // Locations for searching for bios.pk3
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
#define DEFAULTWADLOCATION1 "/usr/local/share/games/RingRacers" #define DEFAULTWADLOCATION1 "/usr/local/share/games/RingRacers"
@ -302,8 +312,10 @@ static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dump
dumpmade ? dumpmade ?
#if defined (UNIXBACKTRACE) #if defined (UNIXBACKTRACE)
"crash-log.txt" "crash-log.txt"
#elif defined (_WIN32) #elif defined (_WIN32) && defined(__GNUC__)
".rpt crash dump" ".rpt crash dump"
#elif defined (USE_DBGHELP)
".dmp crash dump"
#endif #endif
" (very important!) and " : "", " (very important!) and " : "",
#ifdef LOGMESSAGES #ifdef LOGMESSAGES
@ -369,12 +381,83 @@ static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dump
// in case the fullscreen window blocks it for some absurd reason. // in case the fullscreen window blocks it for some absurd reason.
} }
static void I_ReportSignal(int num, int coredumped) static void I_ReportSignal(int num, int coredumped, void* tracefromcpptrace)
{ {
//static char msg[] = "oh no! back to reality!\r\n"; //static char msg[] = "oh no! back to reality!\r\n";
const char * sigmsg; const char * sigmsg;
char msg[128]; char msg[8192];
#ifdef USE_DBGHELP
// The signal code is a WIN32 exception code, not a libc signal
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
switch (num)
{
case EXCEPTION_ACCESS_VIOLATION:
sigmsg = "EXCEPTION_ACCESS_VIOLATION";
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
sigmsg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
break;
case EXCEPTION_BREAKPOINT:
sigmsg = "EXCEPTION_BREAKPOINT";
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
sigmsg = "EXCEPTION_DATATYPE_MISALIGNMENT";
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
sigmsg = "EXCEPTION_FLT_DENORMAL_OPERAND";
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
sigmsg = "EXCEPTION_FLT_DENORMAL_OPERAND";
break;
case EXCEPTION_FLT_INEXACT_RESULT:
sigmsg = "EXCEPTION_FLT_INEXACT_RESULT";
break;
case EXCEPTION_FLT_INVALID_OPERATION:
sigmsg = "EXCEPTION_FLT_INVALID_OPERATION";
break;
case EXCEPTION_FLT_OVERFLOW:
sigmsg = "EXCEPTION_FLT_OVERFLOW";
break;
case EXCEPTION_FLT_STACK_CHECK:
sigmsg = "EXCEPTION_FLT_STACK_CHECK";
break;
case EXCEPTION_FLT_UNDERFLOW:
sigmsg = "EXCEPTION_FLT_UNDERFLOW";
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
sigmsg = "EXCEPTION_ILLEGAL_INSTRUCTION";
break;
case EXCEPTION_IN_PAGE_ERROR:
sigmsg = "EXCEPTION_IN_PAGE_ERROR";
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
sigmsg = "EXCEPTION_INT_DIVIDE_BY_ZERO";
break;
case EXCEPTION_INT_OVERFLOW:
sigmsg = "EXCEPTION_INT_OVERFLOW";
break;
case EXCEPTION_INVALID_DISPOSITION:
sigmsg = "EXCEPTION_INVALID_DISPOSITION";
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
sigmsg = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
break;
case EXCEPTION_PRIV_INSTRUCTION:
sigmsg = "EXCEPTION_PRIV_INSTRUCTION";
break;
case EXCEPTION_SINGLE_STEP:
sigmsg = "EXCEPTION_SINGLE_STEP";
break;
case EXCEPTION_STACK_OVERFLOW:
sigmsg = "EXCEPTION_STACK_OVERFLOW";
break;
default:
sigmsg = "";
sprintf(msg, "unknown exception %d", num);
break;
}
#else
switch (num) switch (num)
{ {
// case SIGINT: // case SIGINT:
@ -405,30 +488,132 @@ static void I_ReportSignal(int num, int coredumped)
else else
sigmsg = msg; sigmsg = msg;
} }
#endif
if (sigmsg)
{
strcpy(msg, sigmsg);
}
if (coredumped) if (coredumped)
{ {
if (sigmsg)
strcpy(msg, sigmsg);
strcat(msg, " (core dumped)"); strcat(msg, " (core dumped)");
}
#ifdef HAVE_CPPTRACE
strncat(msg, "\n", sizeof(msg) - strlen(msg) - 1);
cpptrace::stacktrace const& trace = *(cpptrace::stacktrace*)tracefromcpptrace;
bool firstfound = false;
#ifndef _WIN32
firstfound = true;
#endif
for (const auto& frame : trace)
{
#ifdef _WIN32
// dumb hack, unsure if it works on anything other than windows 10-11
if (!firstfound && frame.symbol == "KiUserExceptionDispatcher")
{
firstfound = true;
continue;
}
if (!firstfound)
{
continue;
}
#endif
srb2::String frame_str;
if (!frame.filename.empty() && frame.line.has_value())
{
frame_str = srb2::format("{} at {}:{}\n", frame.symbol, frame.filename, frame.line.value_or(0));
}
else if (!frame.filename.empty() && !frame.line.has_value())
{
frame_str = srb2::format("{} at {}\n", frame.symbol, frame.filename);
}
else
{
frame_str = srb2::format("{}\n", frame.symbol);
}
strncat(msg, frame_str.c_str(), sizeof(msg) - strlen(msg) - 1);
}
#endif
sigmsg = msg; sigmsg = msg;
}
I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg);
I_ShowErrorMessageBox(sigmsg, I_ShowErrorMessageBox(sigmsg,
#if defined (UNIXBACKTRACE) #if defined (UNIXBACKTRACE)
true true
#elif defined (_WIN32) #elif defined (_WIN32) && defined (__GNUC__)
!M_CheckParm("-noexchndl") !M_CheckParm("-noexchndl")
#elif defined (USE_DBGHELP)
true
#else #else
false false
#endif #endif
); );
} }
#ifndef NEWSIGNALHANDLER #if !defined(NEWSIGNALHANDLER) || defined(USE_DBGHELP)
static void CommonSignalHandleCleanup(void)
{
D_QuitNetGame(); // Fix server freezes
CL_AbortDownloadResume();
G_DirtyGameData();
}
#endif
#ifdef USE_DBGHELP
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_toplevelexceptionfilter;
static LONG WriteMinidumpExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
{
#ifdef HAVE_CPPTRACE
// Fully aware this is completely signal unsafe. We don't ever try to recover from signals, so who cares.
// If it breaks it breaks. We're not mission critical software.
cpptrace::stacktrace trace = cpptrace::generate_trace(0, 30);
#else
int trace = 0;
#endif
MINIDUMP_EXCEPTION_INFORMATION mei {};
mei.ExceptionPointers = ExceptionInfo;
mei.ClientPointers = TRUE;
mei.ThreadId = GetCurrentThreadId();
HANDLE outfile;
char outfilename[1024];
GetModuleFileNameA(NULL, outfilename, sizeof(outfilename));
strncat(outfilename, ".dmp", sizeof(outfilename) - strlen(outfilename) - 1);
outfile = CreateFileA(outfilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (outfile == NULL)
{
return EXCEPTION_CONTINUE_SEARCH;
}
BOOL result;
result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), outfile, MiniDumpNormal, &mei, NULL, NULL);
if (result == FALSE)
{
CloseHandle(outfile);
DeleteFileA("ringracers_minidump.dmp");
goto exit;
}
CloseHandle(outfile);
exit:
CommonSignalHandleCleanup();
I_ReportSignal(ExceptionInfo->ExceptionRecord->ExceptionCode, 0, (void*)&trace);
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
#if !defined(NEWSIGNALHANDLER) && !defined(USE_DBGHELP)
static ATTRNORETURN void signal_handler(INT32 num) static ATTRNORETURN void signal_handler(INT32 num)
{ {
g_in_exiting_signal_handler = true; g_in_exiting_signal_handler = true;
@ -441,18 +626,20 @@ static ATTRNORETURN void signal_handler(INT32 num)
exit(-2); exit(-2);
} }
D_QuitNetGame(); // Fix server freezes CommonSignalHandleCleanup();
CL_AbortDownloadResume();
G_DirtyGameData();
#ifdef UNIXBACKTRACE #ifdef UNIXBACKTRACE
write_backtrace(num); write_backtrace(num);
#endif #endif
I_ReportSignal(num, 0); I_ReportSignal(num, 0, NULL);
signal(num, SIG_DFL); //default signal action signal(num, SIG_DFL); //default signal action
raise(num); raise(num);
} }
#endif #endif
#ifdef USE_DBGHELP
LPTOP_LEVEL_EXCEPTION_FILTER g_prevtoplevelexceptionfilter;
#endif
FUNCNORETURN static ATTRNORETURN void quit_handler(int num) FUNCNORETURN static ATTRNORETURN void quit_handler(int num)
{ {
signal(num, SIG_DFL); //default signal action signal(num, SIG_DFL); //default signal action
@ -829,12 +1016,17 @@ static void I_RegisterSignals (void)
// If these defines don't exist, // If these defines don't exist,
// then compilation would have failed above us... // then compilation would have failed above us...
#ifndef NEWSIGNALHANDLER #if !defined(NEWSIGNALHANDLER) && !defined(USE_DBGHELP)
signal(SIGILL , signal_handler); signal(SIGILL , signal_handler);
signal(SIGSEGV , signal_handler); signal(SIGSEGV , signal_handler);
signal(SIGABRT , signal_handler); signal(SIGABRT , signal_handler);
signal(SIGFPE , signal_handler); signal(SIGFPE , signal_handler);
#endif #endif
#ifdef USE_DBGHELP
// Initialize Windows SDK-specific crashdump handler (DbgHelp)
g_previous_toplevelexceptionfilter = SetUnhandledExceptionFilter(WriteMinidumpExceptionFilter);
#endif
} }
#ifdef NEWSIGNALHANDLER #ifdef NEWSIGNALHANDLER
@ -1598,9 +1790,9 @@ static void I_Fork(void)
{ {
signum = WTERMSIG (status); signum = WTERMSIG (status);
#ifdef WCOREDUMP #ifdef WCOREDUMP
I_ReportSignal(signum, WCOREDUMP (status)); I_ReportSignal(signum, WCOREDUMP (status), NULL);
#else #else
I_ReportSignal(signum, 0); I_ReportSignal(signum, 0, NULL);
#endif #endif
status = 128 + signum; status = 128 + signum;
} }
@ -1656,7 +1848,7 @@ INT32 I_StartupSystem(void)
// //
// I_Quit // I_Quit
// //
void I_Quit(void) FUNCNORETURN void ATTRNORETURN I_Quit(void)
{ {
static SDL_bool quiting = SDL_FALSE; static SDL_bool quiting = SDL_FALSE;
@ -1732,7 +1924,7 @@ static boolean shutdowning = false;
extern "C" consvar_t cv_fuzz; extern "C" consvar_t cv_fuzz;
void I_Error(const char *error, ...) FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...)
{ {
va_list argptr; va_list argptr;
char buffer[8192]; char buffer[8192];

View file

@ -4,6 +4,10 @@
"version": "1.0.0", "version": "1.0.0",
"builtin-baseline": "d5ec528843d29e3a52d745a64b469f810b2cedbf", "builtin-baseline": "d5ec528843d29e3a52d745a64b469f810b2cedbf",
"dependencies": [ "dependencies": [
{
"name": "cpptrace",
"platform": "windows & !mingw"
},
"curl", "curl",
"libogg", "libogg",
"libpng", "libpng",