From b8b0646e9f5e71c0e7d4ca72a9a3916e8b00143d Mon Sep 17 00:00:00 2001 From: maelstrom Date: Mon, 17 Mar 2025 21:38:02 +0100 Subject: [PATCH] feat(logging): replaced unsafe aborts with panic --- core/src/datatypes/meta.cpp | 3 ++- core/src/logger.cpp | 3 ++- core/src/logger.h | 2 ++ core/src/objects/base/instance.cpp | 3 ++- core/src/objects/datamodel.cpp | 5 +++-- core/src/panic.cpp | 29 +++++++++++++++++++++++++++++ core/src/panic.h | 8 ++++++++ core/src/platform.cpp | 4 +++- core/src/rendering/shader.cpp | 5 +++-- core/src/rendering/skybox.cpp | 3 ++- core/src/rendering/texture.cpp | 3 ++- core/src/rendering/texture3d.cpp | 3 ++- 12 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 core/src/panic.cpp create mode 100644 core/src/panic.h diff --git a/core/src/datatypes/meta.cpp b/core/src/datatypes/meta.cpp index f959d2e..ca511b8 100644 --- a/core/src/datatypes/meta.cpp +++ b/core/src/datatypes/meta.cpp @@ -2,6 +2,7 @@ #include "datatypes/base.h" #include "datatypes/cframe.h" #include "logger.h" +#include "panic.h" #include Data::String Data::Variant::ToString() const { @@ -19,7 +20,7 @@ void Data::Variant::Serialize(pugi::xml_node* node) const { Data::Variant Data::Variant::Deserialize(pugi::xml_node* node) { if (Data::TYPE_MAP.count(node->name()) == 0) { Logger::fatalErrorf("Unknown type for instance: '%s'", node->name()); - abort(); + panic(); } const Data::TypeInfo* type = Data::TYPE_MAP[node->name()]; diff --git a/core/src/logger.cpp b/core/src/logger.cpp index 335910c..16620cc 100644 --- a/core/src/logger.cpp +++ b/core/src/logger.cpp @@ -6,6 +6,7 @@ #include static std::ofstream logStream; +std::string Logger::currentLogDir = "NULL"; void Logger::init() { initProgramLogsDir(); @@ -14,7 +15,7 @@ void Logger::init() { std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", now); - logStream = std::ofstream(getProgramLogsDir() + "/" + fileName); + logStream = std::ofstream(currentLogDir = (getProgramLogsDir() + "/" + fileName)); Logger::debug("Logger initialized"); } diff --git a/core/src/logger.h b/core/src/logger.h index 4298ac3..4638971 100644 --- a/core/src/logger.h +++ b/core/src/logger.h @@ -12,6 +12,8 @@ namespace Logger { FATAL_ERROR, }; + extern std::string currentLogDir; + void init(); void finish(); diff --git a/core/src/objects/base/instance.cpp b/core/src/objects/base/instance.cpp index f5e3794..271f59c 100644 --- a/core/src/objects/base/instance.cpp +++ b/core/src/objects/base/instance.cpp @@ -5,6 +5,7 @@ #include "objects/base/member.h" #include "objects/meta.h" #include "logger.h" +#include "panic.h" #include #include #include @@ -171,7 +172,7 @@ InstanceRef Instance::Deserialize(pugi::xml_node* node) { std::string className = node->attribute("class").value(); if (INSTANCE_MAP.count(className) == 0) { Logger::fatalErrorf("Unknown type for instance: '%s'", className.c_str()); - abort(); + panic(); } // This will error if an abstract instance is used in the file. Oh well, not my prob rn. // printf("What are you? A %s sandwich\n", className.c_str()); diff --git a/core/src/objects/datamodel.cpp b/core/src/objects/datamodel.cpp index 9b55e6b..9c1a456 100644 --- a/core/src/objects/datamodel.cpp +++ b/core/src/objects/datamodel.cpp @@ -4,6 +4,7 @@ #include "objects/base/service.h" #include "workspace.h" #include "logger.h" +#include "panic.h" #include #include #include @@ -44,7 +45,7 @@ void DataModel::Init() { void DataModel::SaveToFile(std::optional path) { if (!path.has_value() && !this->currentFile.has_value()) { Logger::fatalError("Cannot save DataModel because no path was provided."); - abort(); + panic(); } std::string target = path.has_value() ? path.value() : this->currentFile.value(); @@ -68,7 +69,7 @@ void DataModel::DeserializeService(pugi::xml_node* node) { std::string className = node->attribute("class").value(); if (SERVICE_CONSTRUCTORS.count(className) == 0) { Logger::fatalErrorf("Unknown service: '%s'", className.c_str()); - abort(); + panic(); } if (services.count(className) != 0) { diff --git a/core/src/panic.cpp b/core/src/panic.cpp new file mode 100644 index 0000000..61fe5bb --- /dev/null +++ b/core/src/panic.cpp @@ -0,0 +1,29 @@ +#include "panic.h" + +#include +#include "logger.h" +#include "platform.h" + +#ifdef _NDEBUG +#define NDEBUG +#endif + +bool trySafeAbort = false; +void panic() { + // We've already been here, safe aborting has failed. + if (trySafeAbort) + abort(); + trySafeAbort = true; + +#ifndef NDEBUG + displayErrorMessage(std::string("A fatal error has occurred and Openblocks had to shut down.\n\ +The currently open document will be attempted to be saved, and logs will be written to " + getProgramLogsDir())); +#endif + + // Finalize logger + Logger::finish(); + + // TODO: Autosave document + + abort(); +} \ No newline at end of file diff --git a/core/src/panic.h b/core/src/panic.h new file mode 100644 index 0000000..ca448a4 --- /dev/null +++ b/core/src/panic.h @@ -0,0 +1,8 @@ +#pragma once + +// Safe and recommended way to abort in case of failure states +// Attempts to create a recovery file for unsaved work and flush logs +// before shutting down. + +// If this process fails, or the panic function is called within itself, it will hard-abort +void panic(); \ No newline at end of file diff --git a/core/src/platform.cpp b/core/src/platform.cpp index bd67175..e274bea 100644 --- a/core/src/platform.cpp +++ b/core/src/platform.cpp @@ -1,5 +1,7 @@ #include "platform.h" + #include +#include "panic.h" // GNU/Linux implementation #if defined(_POSIX_VERSION) || defined(__linux) || defined(__linux__) @@ -41,7 +43,7 @@ std::string getProgramDataDir() { int status = SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, localAppData); if (status != 0) { printErrorMessage("Failed to find local appdata folder"); - abort(); + panic(); } return localAppData + "/openblocks"; } diff --git a/core/src/rendering/shader.cpp b/core/src/rendering/shader.cpp index 6784614..efdfd81 100644 --- a/core/src/rendering/shader.cpp +++ b/core/src/rendering/shader.cpp @@ -4,6 +4,7 @@ #include #include "logger.h" +#include "panic.h" #include "shader.h" std::string getContents(std::string filePath) { @@ -27,7 +28,7 @@ unsigned int compileShader(std::string path, GLenum type) { char infoLog[256]; glGetShaderInfoLog(shader, 512, NULL, infoLog); Logger::fatalErrorf("Fragment shader %s failed to compile: [%d]: %s", path.c_str(), success, infoLog); - abort(); + panic(); } return shader; @@ -48,7 +49,7 @@ Shader::Shader(std::string vertexShaderPath, std::string fragmentShaderPath) { char infoLog[256]; glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); Logger::fatalErrorf("Shader program failed to link: [%d]: %s", success, infoLog); - abort(); + panic(); } glDeleteShader(vertexShader); diff --git a/core/src/rendering/skybox.cpp b/core/src/rendering/skybox.cpp index 6aad73c..b7dee51 100644 --- a/core/src/rendering/skybox.cpp +++ b/core/src/rendering/skybox.cpp @@ -3,6 +3,7 @@ #include #include "logger.h" +#include "panic.h" #include "skybox.h" Skybox::Skybox(std::array faces, unsigned int format) { @@ -17,7 +18,7 @@ Skybox::Skybox(std::array faces, unsigned int format) { if (!data) { Logger::fatalErrorf("Failed to load texture '%s'", faces[i].c_str()); - abort(); + panic(); } glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, format, diff --git a/core/src/rendering/texture.cpp b/core/src/rendering/texture.cpp index ea6bb15..db0c8d2 100644 --- a/core/src/rendering/texture.cpp +++ b/core/src/rendering/texture.cpp @@ -4,6 +4,7 @@ #include #include +#include "panic.h" #include "logger.h" Texture::Texture(const char* texturePath, unsigned int format, bool noMipMaps) { @@ -25,7 +26,7 @@ Texture::Texture(const char* texturePath, unsigned int format, bool noMipMaps) { if (!data) { Logger::fatalErrorf("Failed to load texture '%s'", texturePath); - abort(); + panic(); } glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, diff --git a/core/src/rendering/texture3d.cpp b/core/src/rendering/texture3d.cpp index 8c92828..530bcb8 100644 --- a/core/src/rendering/texture3d.cpp +++ b/core/src/rendering/texture3d.cpp @@ -4,6 +4,7 @@ #include #include +#include "panic.h" #include "logger.h" Texture3D::Texture3D(const char* texturePath, unsigned int tileWidth, unsigned int tileHeight, unsigned int tileCount, unsigned int format) { @@ -26,7 +27,7 @@ Texture3D::Texture3D(const char* texturePath, unsigned int tileWidth, unsigned i if (!data) { Logger::fatalErrorf("Failed to load texture '%s'", texturePath); - abort(); + panic(); } glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, format, tileWidth, tileHeight, /* no of layers= */ tileCount, 0, format,