From c9d0e86344f12eda5bc8ab40a0043476f0582acf Mon Sep 17 00:00:00 2001 From: Ondrej Novak Date: Wed, 12 Mar 2025 18:59:47 +0100 Subject: [PATCH] add some cheks and error reporting, enable catch SEH in windows --- CMakeLists.txt | 2 +- game/builder.c | 1 - game/skeldal.c | 3 +- platform/error.h | 2 + platform/legacy_coroutines.cpp | 21 ++++++++-- platform/sdl/sdl_context.cpp | 71 ++++++++++++++++++++++------------ platform/sdl/sound.cpp | 18 +++++++-- platform/windows/app_start.cpp | 4 ++ 8 files changed, 88 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f937be8..6f8dc14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(skeldal) find_package(SDL2 REQUIRED) if (MSVC) - add_compile_options(/W4 /EHsc /DNOMINMAX /J) + add_compile_options(/W4 /EHa /DNOMINMAX /J) set(STANDARD_LIBRARIES "") else() add_compile_options(-Wall -Wextra -Werror -Wno-unused-result -Wno-unused-parameter -Wno-unused-value -Wno-extern-c-compat -funsigned-char) diff --git a/game/builder.c b/game/builder.c index 478763a..914bba4 100644 --- a/game/builder.c +++ b/game/builder.c @@ -1375,7 +1375,6 @@ void redraw_scene() ukaz_mysku(); global_anim_counter++; send_message(E_KOUZLO_ANM); - } void refresh_scene(THE_TIMER *t) diff --git a/game/skeldal.c b/game/skeldal.c index fd7d495..60fd265 100644 --- a/game/skeldal.c +++ b/game/skeldal.c @@ -996,7 +996,8 @@ void init_skeldal(const INI_CONFIG *cfg) char verr = game_display_init(ini_section_open(cfg, "video"), "Skeldal"); if (!verr) { - exit(1); + display_error("Error game_display_init %d", verr); + exit(1); } showview = game_display_update_rect; game_display_set_icon(getWindowIcon(), getWindowIconSize()); diff --git a/platform/error.h b/platform/error.h index 784c51c..5b86ccd 100644 --- a/platform/error.h +++ b/platform/error.h @@ -7,6 +7,8 @@ extern "C" { void send_log_impl(const char *format, ...); +void display_error(const char *format, ...); + #ifdef __cplusplus } diff --git a/platform/legacy_coroutines.cpp b/platform/legacy_coroutines.cpp index 45a0d93..2d76fbd 100644 --- a/platform/legacy_coroutines.cpp +++ b/platform/legacy_coroutines.cpp @@ -1,5 +1,5 @@ #include "legacy_coroutines.h" - +#include "error.h" #include #include @@ -116,6 +116,17 @@ static void broadcast_message(EVENT_MSG *msg) { clean_task_table(); } +static void crash_task_exception() { + try { + throw; + } catch (std::exception &e) { + display_error("Unhandled exception in task %d: %s",q_current_task(), e.what()); + } catch (...) { + display_error("Unhandled exception in task %d: unknown/crash",q_current_task()); + } + abort(); +} + int add_task(int stack,TaskerFunctionName fcname,...) { int id = get_new_task_id(); @@ -126,8 +137,12 @@ int add_task(int stack,TaskerFunctionName fcname,...) { new_task->thr = std::thread([&]{ new_task->resume_flag.wait(false); new_task->resume_flag = false; - fcname(args); - clean_up_current_task(); + try { + fcname(args); + clean_up_current_task(); + } catch (...) { + crash_task_exception(); + } }); switch_to_task(new_task); return id; diff --git a/platform/sdl/sdl_context.cpp b/platform/sdl/sdl_context.cpp index c241c7a..185cdae 100644 --- a/platform/sdl/sdl_context.cpp +++ b/platform/sdl/sdl_context.cpp @@ -63,6 +63,12 @@ SDLContext::SDLContext() { if (!init_context.inited) throw std::runtime_error("SDL not inited"); } +void handle_sdl_error(const char *msg) { + char buff[512]; + + snprintf(buff, sizeof(buff), "SDL critical error (check video driver): %s %s",msg, SDL_GetError()); + throw std::runtime_error(buff); +} void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** texture, int width, int height, CrtFilterType type) { @@ -78,20 +84,27 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur } // Vytvoř novou texturu ve správné velikosti *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); + if (!*texture) { + type = CrtFilterType::none; + return; //crt filter failed to create, do not use filter + } SDL_SetTextureBlendMode(*texture, SDL_BLENDMODE_MUL); // Zamkni texturu pro přímý přístup k pixelům void* pixels; int pitch; - SDL_LockTexture(*texture, nullptr, &pixels, &pitch); + if (SDL_LockTexture(*texture, nullptr, &pixels, &pitch)<0) { + SDL_DestroyTexture(*texture); + *texture = nullptr; + type = CrtFilterType::none; + return; + } Uint32* pixelArray = (Uint32*)pixels; if (type == CrtFilterType::scanlines) { - - Uint32 darkPixel = 0xA0A0A0FF; Uint32 transparentPixel = 0xFFFFFFC0; @@ -152,10 +165,19 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur SDL_UnlockTexture(*texture); } +static void crash_sdl_exception() { + try { + throw; + } catch (std::exception &e) { + display_error("Display server - unhandled exception: %s", e.what()); + } catch (...) { + display_error("Display server - unhandled unknown exception (probably crash)"); + } + abort(); +} void SDLContext::init_video(const VideoConfig &config, const char *title) { - char buff[256]; static Uint32 update_request_event = SDL_RegisterEvents(1); static Uint32 refresh_request_event = SDL_RegisterEvents(1); _update_request_event = update_request_event; @@ -187,15 +209,13 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) { width, height, SDL_WINDOW_RESIZABLE|(_fullscreen_mode?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); if (!window) { - snprintf(buff, sizeof(buff), "SDL Error create window: %s\n", SDL_GetError()); - throw std::runtime_error(buff); + handle_sdl_error("SDL Error create window"); } _window.reset(window); SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, config.composer); if (!renderer) { - snprintf(buff,sizeof(buff), "Failed to create composer: %s\n", SDL_GetError()); - throw std::runtime_error(buff); + handle_sdl_error("Failed to create composer"); } SDL_RendererInfo rinfo; @@ -212,15 +232,14 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) { _renderer.reset(renderer); SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480); if (!texture) { - snprintf(buff, sizeof(buff), "Chyba při vytváření textury: %s\n", SDL_GetError()); - throw std::runtime_error(buff); + handle_sdl_error("Failed to create render target"); } + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); _texture.reset(texture); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480); if (!texture) { - snprintf(buff, sizeof(buff), "Chyba při vytváření textury: %s\n", SDL_GetError()); - throw std::runtime_error(buff); + handle_sdl_error("Failed to create second render target"); } SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); _texture2.reset(texture); @@ -232,8 +251,16 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) { } done = true; done.notify_all(); - SDL_ShowCursor(SDL_DISABLE); - if (!err) event_loop(stp); + + if (!err) { + try { + SDL_ShowCursor(SDL_DISABLE); + event_loop(stp); + } catch (...) { + SDL_ShowCursor(SDL_ENABLE); + crash_sdl_exception(); + } + } _texture.reset(); _texture2.reset(); _renderer.reset(); @@ -648,7 +675,7 @@ void SDLContext::update_screen(bool force_refresh) { SDL_Rect r; pop_item(iter, r); std::string_view data = pop_data(iter, r.w*r.h*2); - SDL_UpdateTexture(_texture.get(), &r, data.data(), r.w*2); + if (SDL_UpdateTexture(_texture.get(), &r, data.data(), r.w*2)<0) handle_sdl_error("Update of render target failed"); } break; case DisplayRequest::show_mouse_cursor: { @@ -656,10 +683,11 @@ void SDLContext::update_screen(bool force_refresh) { pop_item(iter, r); std::string_view data = pop_data(iter, r.w*r.h*2); _mouse.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555,SDL_TEXTUREACCESS_STATIC, r.w, r.h)); + if (!_mouse) handle_sdl_error("Failed to create surface for mouse cursor"); SDL_SetTextureBlendMode(_mouse.get(), SDL_BLENDMODE_BLEND); _mouse_rect.w = r.w; _mouse_rect.h = r.h; - SDL_UpdateTexture(_mouse.get(), NULL, data.data(), r.w*2); + if (SDL_UpdateTexture(_mouse.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of mouse cursor failed"); } break; case DisplayRequest::hide_mouse_cursor: { @@ -697,8 +725,9 @@ void SDLContext::update_screen(bool force_refresh) { iter = _sprites.insert(iter,{id}); } iter->_txtr.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STATIC,r.w, r.h)); + if (!iter->_txtr) handle_sdl_error("Failed to create compositor sprite"); SDL_SetTextureBlendMode(iter->_txtr.get(), SDL_BLENDMODE_BLEND); - SDL_UpdateTexture(iter->_txtr.get(), NULL, data.data(), r.w*2); + if (SDL_UpdateTexture(iter->_txtr.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of sprite failed"); iter->_rect = r; update_zindex(); } break; @@ -947,13 +976,7 @@ void SDLContext::close_audio() { void SDLContext::set_window_icon(const void *icon_data, size_t icon_size) { SDL_Surface *surface = SDL_LoadBMP_RW(SDL_RWFromConstMem(icon_data, icon_size), 1); - if (surface == 0) { - char buff[256]; - snprintf(buff,sizeof(buff),"Can't load icon: %s", SDL_GetError()); - display_error(buff); - std::ofstream x("test.dat", std::ios::out|std::ios::binary|std::ios::trunc); - x.write(reinterpret_cast(icon_data), icon_size); - } else { + if (surface) { SDL_SetWindowIcon(_window.get(), surface); } } diff --git a/platform/sdl/sound.cpp b/platform/sdl/sound.cpp index d59c495..6c2c562 100644 --- a/platform/sdl/sound.cpp +++ b/platform/sdl/sound.cpp @@ -50,10 +50,20 @@ void game_sound_init_device(const INI_CONFIG_SECTION *audio_section) { } static void SDLCALL mixing_callback(void *userdata, Uint8 * stream, int len) { - float *s = reinterpret_cast(stream); - int samples = len/8; - std::fill(s, s+2*samples, 0.0f); - sound_mixer.mix_to_buffer(s, samples); + static char crashed = 0; + float *s = reinterpret_cast(stream); + int samples = len/8; + std::fill(s, s+2*samples, 0.0f); + if (crashed) return; + try { + sound_mixer.mix_to_buffer(s, samples); + } catch (std::exception &e) { + crashed = 1; + display_error("Unhandled exception in sound mixer: %s", e.what()); + } catch (...) { + crashed = 1; + display_error("Crash in sound mixer: %s"); + } } char start_mixing() { diff --git a/platform/windows/app_start.cpp b/platform/windows/app_start.cpp index 19282c2..8ecc5a9 100644 --- a/platform/windows/app_start.cpp +++ b/platform/windows/app_start.cpp @@ -85,6 +85,10 @@ int main(int argc, char **argv) { cfg.show_error(e.what()); return 1; } + catch (...) { + cfg.show_error("Uknown error or crash"); + return 1; + } return 0;