diff --git a/.gitmodules b/.gitmodules index c773416e3b..f1fabee4b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,7 +16,7 @@ ignore = dirty [submodule "3rdparty/cereal"] path = 3rdparty/cereal - url = https://github.com/USCiLab/cereal.git + url = https://github.com/RPCS3/cereal.git ignore = dirty [submodule "3rdparty/zlib"] path = 3rdparty/zlib @@ -37,7 +37,7 @@ ignore = dirty [submodule "3rdparty/yaml-cpp"] path = 3rdparty/yaml-cpp - url = https://github.com/jbeder/yaml-cpp.git + url = https://github.com/RPCS3/yaml-cpp.git ignore = dirty [submodule "3rdparty/libpng"] path = 3rdparty/libpng diff --git a/3rdparty/cereal b/3rdparty/cereal index 42a45b6e15..60c69df968 160000 --- a/3rdparty/cereal +++ b/3rdparty/cereal @@ -1 +1 @@ -Subproject commit 42a45b6e15fcbd1a3d65b033f5d4d0b2ef6c023d +Subproject commit 60c69df968d1c72c998cd5f23ba34e2e3718a84b diff --git a/3rdparty/yaml-cpp b/3rdparty/yaml-cpp index eca9cfd648..6a211f0bc7 160000 --- a/3rdparty/yaml-cpp +++ b/3rdparty/yaml-cpp @@ -1 +1 @@ -Subproject commit eca9cfd64899525d0a61abb0553849676a0fe511 +Subproject commit 6a211f0bc71920beef749e6c35d7d1bcc2447715 diff --git a/3rdparty/yaml-cpp.vcxproj b/3rdparty/yaml-cpp.vcxproj index 849068e0d6..6add456fb1 100644 --- a/3rdparty/yaml-cpp.vcxproj +++ b/3rdparty/yaml-cpp.vcxproj @@ -37,6 +37,11 @@ + + + Sync + + diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 3c59881acb..28732b817e 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -1,11 +1,14 @@ #include "stdafx.h" #include "Config.h" +#include "Utilities/types.h" -#include "yaml-cpp/yaml.h" +#include "util/yaml.hpp" #include #include +[[noreturn]] void report_fatal_error(const std::string&); + LOG_CHANNEL(cfg_log, "CFG"); namespace cfg @@ -15,7 +18,7 @@ namespace cfg { if (_type != type::node) { - fmt::throw_exception("Invalid root node" HERE); + cfg_log.fatal("Invalid root node" HERE); } } @@ -26,7 +29,7 @@ namespace cfg { if (pair.first == name) { - fmt::throw_exception("Node already exists: %s" HERE, name); + cfg_log.fatal("Node already exists: %s" HERE, name); } } @@ -35,12 +38,12 @@ namespace cfg bool _base::from_string(const std::string&, bool) { - fmt::throw_exception("from_string() purecall" HERE); + report_fatal_error("from_string() purecall" HERE); } bool _base::from_list(std::vector&&) { - fmt::throw_exception("from_list() purecall" HERE); + report_fatal_error("from_list() purecall" HERE); } // Emit YAML @@ -302,14 +305,17 @@ std::string cfg::node::to_string() const return {out.c_str(), out.size()}; } -bool cfg::node::from_string(const std::string& value, bool dynamic) try +bool cfg::node::from_string(const std::string& value, bool dynamic) { - cfg::decode(YAML::Load(value), *this, dynamic); - return true; -} -catch (const std::exception& e) -{ - cfg_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); + auto [result, error] = yaml_load(value); + + if (error.empty()) + { + cfg::decode(result, *this, dynamic); + return true; + } + + cfg_log.fatal("Failed to load node: %s", error); return false; } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index a0efec6ead..8655a82397 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -60,22 +60,6 @@ void fmt_class_string::format(std::string& out, u64 arg) out += ss.str(); } -[[noreturn]] void catch_all_exceptions() -{ - try - { - throw; - } - catch (const std::exception& e) - { - report_fatal_error("{" + g_tls_log_prefix() + "} Unhandled exception of type '"s + typeid(e).name() + "': "s + e.what()); - } - catch (...) - { - report_fatal_error("{" + g_tls_log_prefix() + "} Unhandled exception (unknown)"); - } -} - #ifndef _WIN32 bool IsDebuggerPresent() { @@ -1151,33 +1135,12 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no if (rsx::g_access_violation_handler) { - bool handled = false; - - try + if (cpu) { - if (cpu) - { - vm::temporary_unlock(*cpu); - } - - handled = rsx::g_access_violation_handler(addr, is_writing); + vm::temporary_unlock(*cpu); } - catch (const std::exception& e) - { - rsx_log.fatal("g_access_violation_handler(0x%x, %d): %s", addr, is_writing, e.what()); - if (cpu) - { - cpu->state += cpu_flag::dbg_pause; - - if (cpu->test_stopped()) - { - std::terminate(); - } - } - - return false; - } + bool handled = rsx::g_access_violation_handler(addr, is_writing); if (handled) { @@ -1769,7 +1732,7 @@ const bool s_exception_handler_set = []() -> bool if (::sigaction(SIGSEGV, &sa, NULL) == -1) { - std::fprintf(stderr, "sigaction(SIGSEGV) failed (0x%x).", errno); + std::fprintf(stderr, "sigaction(SIGSEGV) failed (%d).\n", errno); std::abort(); } @@ -1779,6 +1742,23 @@ const bool s_exception_handler_set = []() -> bool #endif +const bool s_terminate_handler_set = []() -> bool +{ + std::set_terminate([]() + { + if (IsDebuggerPresent()) +#ifdef _MSC_VER + __debugbreak(); +#else + __asm("int3;"); +#endif + + report_fatal_error("RPCS3 has abnormally terminated."); + }); + + return true; +}(); + thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined }; diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 028645dbb3..e58e8fad90 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -15,9 +15,6 @@ // Report error and call std::abort(), defined in main.cpp [[noreturn]] void report_fatal_error(const std::string&); -// Will report exception and call std::abort() if put in catch(...) -[[noreturn]] void catch_all_exceptions(); - // Hardware core layout enum class native_core_arrangement : u32 { @@ -256,9 +253,9 @@ class named_thread final : public Context, result_storage_t, thread_bas // Type-erased thread entry point #ifdef _WIN32 - static inline uint __stdcall entry_point(void* arg) try + static inline uint __stdcall entry_point(void* arg) #else - static inline void* entry_point(void* arg) try + static inline void* entry_point(void* arg) #endif { const auto _this = static_cast(static_cast(arg)); @@ -272,10 +269,6 @@ class named_thread final : public Context, result_storage_t, thread_bas thread::finalize(); return 0; } - catch (...) - { - catch_all_exceptions(); - } bool entry_point() { diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp index 4765f41c09..18a5cd6c6b 100644 --- a/Utilities/bin_patch.cpp +++ b/Utilities/bin_patch.cpp @@ -1,5 +1,5 @@ #include "bin_patch.h" -#include +#include "util/yaml.hpp" #include "File.h" #include "Config.h" @@ -34,15 +34,11 @@ void patch_engine::append(const std::string& patch) { if (fs::file f{patch}) { - YAML::Node root; + auto [root, error] = yaml_load(f.to_string()); - try + if (!error.empty()) { - root = YAML::Load(f.to_string()); - } - catch (const std::exception& e) - { - patch_log.fatal("Failed to load patch file %s\n%s thrown: %s", patch, typeid(e).name(), e.what()); + patch_log.fatal("Failed to load patch file %s:\n%s", patch, error); return; } diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index ceba08fe1b..c45dbbe30d 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -32,6 +32,8 @@ target_sources(rpcs3_emu PRIVATE ../util/shared_cptr.cpp ../util/fixed_typemap.cpp ../util/logs.cpp + ../util/yaml.cpp + ../util/cereal.cpp ../../Utilities/bin_patch.cpp ../../Utilities/cond.cpp ../../Utilities/Config.cpp @@ -62,6 +64,12 @@ else() set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES COMPILE_FLAGS -fno-rtti) endif() +if (MSVC) + set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS /EHsc) +else() + set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions) +endif() + # Crypto target_sources(rpcs3_emu PRIVATE diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index ffbe3d98ab..aacbd9c42d 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -243,28 +243,83 @@ using cpu_profiler = named_thread; thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; -// For synchronizing suspend_all operation -alignas(64) shared_mutex g_cpu_suspend_lock; +struct cpu_counter +{ + // For synchronizing suspend_all operation + alignas(64) shared_mutex cpu_suspend_lock; -// Semaphore for global thread array (global counter) -alignas(64) atomic_t g_cpu_array_sema{0}; + // Semaphore for global thread array (global counter) + alignas(64) atomic_t cpu_array_sema{0}; -// Semaphore subdivision for each array slot (64 x N in total) -atomic_t g_cpu_array_bits[6]{}; + // Semaphore subdivision for each array slot (64 x N in total) + atomic_t cpu_array_bits[6]{}; -// All registered threads -atomic_t g_cpu_array[sizeof(g_cpu_array_bits) * 8]{}; + // All registered threads + atomic_t cpu_array[sizeof(cpu_array_bits) * 8]{}; + + u64 add(cpu_thread* _this) + { + if (!cpu_array_sema.try_inc(sizeof(cpu_counter::cpu_array_bits) * 8)) + { + return -1; + } + + u64 array_slot = -1; + + for (u32 i = 0;; i = (i + 1) % ::size32(cpu_array_bits)) + { + const auto [bits, ok] = cpu_array_bits[i].fetch_op([](u64& bits) -> u64 + { + if (~bits) [[likely]] + { + // Set lowest clear bit + bits |= bits + 1; + return true; + } + + return false; + }); + + if (ok) [[likely]] + { + // Get actual slot number + array_slot = i * 64 + utils::cnttz64(~bits, false); + break; + } + } + + // Register and wait if necessary + verify("cpu_counter::add()" HERE), cpu_array[array_slot].exchange(_this) == nullptr; + + _this->state += cpu_flag::wait; + cpu_suspend_lock.lock_unlock(); + return array_slot; + } + + void remove(cpu_thread* _this, u64 slot) + { + // Unregister and wait if necessary + _this->state += cpu_flag::wait; + if (cpu_array[slot].exchange(nullptr) != _this) + sys_log.fatal("Inconsistency for array slot %u", slot); + cpu_array_bits[slot / 64] &= ~(1ull << (slot % 64)); + cpu_array_sema--; + cpu_suspend_lock.lock_unlock(); + } +}; template void for_all_cpu(F&& func) noexcept { - for (u32 i = 0; i < ::size32(g_cpu_array_bits); i++) + auto ctr = g_fxo->get(); + + for (u32 i = 0; i < ::size32(ctr->cpu_array_bits); i++) { - for (u64 bits = g_cpu_array_bits[i]; bits; bits &= bits - 1) + for (u64 bits = ctr->cpu_array_bits[i]; bits; bits &= bits - 1) { const u64 index = i * 64 + utils::cnttz64(bits, true); - if (cpu_thread* cpu = g_cpu_array[index].load()) + if (cpu_thread* cpu = ctr->cpu_array[index].load()) { func(cpu); } @@ -301,6 +356,12 @@ void cpu_thread::operator()() } } + while (!g_fxo->get() && !g_fxo->get()) + { + // Can we have a little race, right? First thread is started concurrently with g_fxo->init() + std::this_thread::sleep_for(1ms); + } + if (id_type() == 1 && false) { g_fxo->get()->registered.push(id); @@ -312,67 +373,51 @@ void cpu_thread::operator()() } // Register thread in g_cpu_array - if (!g_cpu_array_sema.try_inc(sizeof(g_cpu_array_bits) * 8)) + const u64 array_slot = g_fxo->get()->add(this); + + if (array_slot == umax) { sys_log.fatal("Too many threads."); return; } - u64 array_slot = -1; - - for (u32 i = 0;; i = (i + 1) % ::size32(g_cpu_array_bits)) - { - const auto [bits, ok] = g_cpu_array_bits[i].fetch_op([](u64& bits) -> u64 - { - if (~bits) [[likely]] - { - // Set lowest clear bit - bits |= bits + 1; - return true; - } - - return false; - }); - - if (ok) [[likely]] - { - // Get actual slot number - array_slot = i * 64 + utils::cnttz64(~bits, false); - break; - } - } - - // Register and wait if necessary - verify("g_cpu_array[...] -> this" HERE), g_cpu_array[array_slot].exchange(this) == nullptr; - - state += cpu_flag::wait; - g_cpu_suspend_lock.lock_unlock(); - static thread_local struct thread_cleanup_t { cpu_thread* _this; u64 slot; + std::string name; thread_cleanup_t(cpu_thread* _this, u64 slot) : _this(_this) , slot(slot) + , name(thread_ctrl::get_name()) { } - ~thread_cleanup_t() + void cleanup() { + if (_this == nullptr) + { + return; + } + if (auto ptr = vm::g_tls_locked) { ptr->compare_and_swap(_this, nullptr); } - // Unregister and wait if necessary - _this->state += cpu_flag::wait; - if (g_cpu_array[slot].exchange(nullptr) != _this) - sys_log.fatal("Inconsistency for array slot %u", slot); - g_cpu_array_bits[slot / 64] &= ~(1ull << (slot % 64)); - g_cpu_array_sema--; - g_cpu_suspend_lock.lock_unlock(); + g_fxo->get()->remove(_this, slot); + + _this = nullptr; + } + + ~thread_cleanup_t() + { + if (_this) + { + sys_log.warning("CPU Thread '%s' terminated abnormally:\n%s", name, _this->dump()); + cleanup(); + } } } cleanup{this, array_slot}; @@ -382,23 +427,16 @@ void cpu_thread::operator()() // Check stop status if (!(state & cpu_flag::stop)) { - try - { - cpu_task(); - } - catch (const std::exception& e) - { - sys_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); - sys_log.notice("\n%s", dump()); - break; - } - + cpu_task(); state -= cpu_flag::ret; continue; } thread_ctrl::wait(); } + + // Complete cleanup gracefully + cleanup.cleanup(); } cpu_thread::~cpu_thread() @@ -493,7 +531,7 @@ bool cpu_thread::check_state() noexcept else { // If only cpu_flag::pause was set, notification won't arrive - g_cpu_suspend_lock.lock_unlock(); + g_fxo->get()->cpu_suspend_lock.lock_unlock(); } } @@ -577,7 +615,7 @@ cpu_thread::suspend_all::suspend_all(cpu_thread* _this) noexcept m_this->state += cpu_flag::wait; } - g_cpu_suspend_lock.lock_vip(); + g_fxo->get()->cpu_suspend_lock.lock_vip(); for_all_cpu([](cpu_thread* cpu) { @@ -610,18 +648,18 @@ cpu_thread::suspend_all::suspend_all(cpu_thread* _this) noexcept cpu_thread::suspend_all::~suspend_all() { // Make sure the latest thread does the cleanup and notifies others - if (g_cpu_suspend_lock.downgrade_unique_vip_lock_to_low_or_unlock()) + if (g_fxo->get()->cpu_suspend_lock.downgrade_unique_vip_lock_to_low_or_unlock()) { for_all_cpu([&](cpu_thread* cpu) { cpu->state -= cpu_flag::pause; }); - g_cpu_suspend_lock.unlock_low(); + g_fxo->get()->cpu_suspend_lock.unlock_low(); } else { - g_cpu_suspend_lock.lock_unlock(); + g_fxo->get()->cpu_suspend_lock.lock_unlock(); } if (m_this) @@ -640,7 +678,7 @@ void cpu_thread::stop_all() noexcept } else { - ::vip_lock lock(g_cpu_suspend_lock); + ::vip_lock lock(g_fxo->get()->cpu_suspend_lock); for_all_cpu([](cpu_thread* cpu) { @@ -651,7 +689,7 @@ void cpu_thread::stop_all() noexcept sys_log.notice("All CPU threads have been signaled."); - while (g_cpu_array_sema) + while (g_fxo->get()->cpu_array_sema) { std::this_thread::sleep_for(10ms); } diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 17826f78de..f3b0944408 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -138,15 +138,9 @@ struct content_permission final bool success = false; fs::g_tls_error = fs::error::ok; - try - { - if (temp.size() <= 1 || fs::remove_all(temp)) - { - success = true; - } - } - catch (...) + if (temp.size() <= 1 || fs::remove_all(temp)) { + success = true; } if (!success) diff --git a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp index d3b899e4eb..ee83107071 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -151,7 +151,7 @@ void pngDecError(png_structp png_ptr, png_const_charp error_message) { cellPngDec.error("%s", error_message); // we can't return here or libpng blows up - throw LibPngCustomException("Fatal Error in libpng"); + report_fatal_error("Fatal Error in libpng"); } // Custom warning handler for libpng @@ -486,14 +486,7 @@ s32 pngDecOpen(ppu_thread& ppu, PHandle handle, PPStream png_stream, PSrc source png_set_progressive_read_fn(stream->png_ptr, stream.get_ptr(), pngDecInfoCallback, pngDecRowCallback, pngDecEndCallback); // push header tag to libpng to keep us in sync - try - { - png_process_data(stream->png_ptr, stream->info_ptr, header, 8); - } - catch (LibPngCustomException&) - { - return CELL_PNGDEC_ERROR_HEADER; - } + png_process_data(stream->png_ptr, stream->info_ptr, header, 8); } else { @@ -729,15 +722,7 @@ s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr d if (stream->buffer->length > stream->buffer->cursor) { u8* data = static_cast(stream->buffer->data.get_ptr()) + stream->buffer->cursor; - try - { - png_process_data(stream->png_ptr, stream->info_ptr, data, stream->buffer->length - stream->buffer->cursor); - } - catch (LibPngCustomException&) - { - freeMem(); - return CELL_PNGDEC_ERROR_FATAL; - } + png_process_data(stream->png_ptr, stream->info_ptr, data, stream->buffer->length - stream->buffer->cursor); streamInfo->decodedStrmSize = ::narrow(stream->buffer->length); } @@ -747,15 +732,7 @@ s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr d { stream->cbCtrlStream.cbCtrlStrmFunc(ppu, streamInfo, streamParam, stream->cbCtrlStream.cbCtrlStrmArg); streamInfo->decodedStrmSize += streamParam->strmSize; - try - { - png_process_data(stream->png_ptr, stream->info_ptr, static_cast(streamParam->strmPtr.get_ptr()), streamParam->strmSize); - } - catch (LibPngCustomException&) - { - freeMem(); - return CELL_PNGDEC_ERROR_FATAL; - } + png_process_data(stream->png_ptr, stream->info_ptr, static_cast(streamParam->strmPtr.get_ptr()), streamParam->strmSize); } freeMem(); @@ -767,7 +744,6 @@ s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr d // Decode the image // todo: commandptr - try { for (u32 j = 0; j < stream->passes; j++) { @@ -779,10 +755,6 @@ s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr d } png_read_end(stream->png_ptr, stream->info_ptr); } - catch (LibPngCustomException&) - { - return CELL_PNGDEC_ERROR_FATAL; - } } // Get the number of iTXt, tEXt and zTXt chunks @@ -862,14 +834,7 @@ s32 cellPngDecExtReadHeader(PHandle handle, PStream stream, PInfo info, PExtInfo // lets push what we have so far u8* data = static_cast(stream->buffer->data.get_ptr()) + stream->buffer->cursor; - try - { - png_process_data(stream->png_ptr, stream->info_ptr, data, stream->buffer->length); - } - catch (LibPngCustomException&) - { - return CELL_PNGDEC_ERROR_HEADER; - } + png_process_data(stream->png_ptr, stream->info_ptr, data, stream->buffer->length); // lets hope we pushed enough for callback pngSetHeader(stream.get_ptr()); diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp index 477e5378ae..f95c37568d 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -114,7 +114,9 @@ void cellSpursModuleExit(spu_thread& spu) { auto ctxt = vm::_ptr(spu.offset + 0x100); spu.pc = ctxt->exitToKernelAddr; - throw SpursModuleExit(); + + // TODO: use g_escape for actual long jump + //throw SpursModuleExit(); } // Execute a DMA operation @@ -728,7 +730,6 @@ bool spursSysServiceEntry(spu_thread& spu) auto arg = spu.gpr[4]._u64[1]; auto pollStatus = spu.gpr[5]._u32[3]; - try { if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { @@ -743,10 +744,6 @@ bool spursSysServiceEntry(spu_thread& spu) cellSpursModuleExit(spu); } - catch (SpursModuleExit) - { - } - return false; } @@ -1326,7 +1323,6 @@ bool spursTasksetEntry(spu_thread& spu) //spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry); //spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry); - try { // Initialise the taskset policy module spursTasksetInit(spu, pollStatus); @@ -1334,9 +1330,6 @@ bool spursTasksetEntry(spu_thread& spu) // Dispatch spursTasksetDispatch(spu); } - catch (SpursModuleExit) - { - } return false; } @@ -1346,7 +1339,6 @@ bool spursTasksetSyscallEntry(spu_thread& spu) { auto ctxt = vm::_ptr(spu.offset + 0x2700); - try { // Save task context ctxt->savedContextLr = spu.gpr[0]; @@ -1365,9 +1357,6 @@ bool spursTasksetSyscallEntry(spu_thread& spu) // spursTasksetResumeTask(spu); //} } - catch (SpursModuleExit) - { - } return false; } diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index c6424ba131..fdf3c6defa 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -5,7 +5,7 @@ #include "PPUModule.h" #include -#include "yaml-cpp/yaml.h" +#include "util/yaml.hpp" #include "Utilities/asm.h" LOG_CHANNEL(ppu_validator); @@ -54,7 +54,13 @@ void ppu_module::validate(u32 reloc) // Load custom PRX configuration if available if (fs::file yml{path + ".yml"}) { - const auto cfg = YAML::Load(yml.to_string()); + const auto [cfg, error] = yaml_load(yml.to_string()); + + if (!error.empty()) + { + ppu_validator.error("Failed to load %s.yml: %s", path, error); + return; + } u32 index = 0; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index a516c4a9a0..e84ff28cd7 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -859,16 +859,7 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc) } }; - try - { - exec_task(); - } - catch (...) - { - at_ret(); - throw; - } - + exec_task(); at_ret(); } diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index ad23ba97cd..72c4a16cfc 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -4357,7 +4357,7 @@ Value* PPUTranslator::GetVr(u32 vr, VrType type) case VrType::i128: return m_ir->CreateBitCast(value, GetType()); } - throw std::logic_error("GetVr(): invalid type"); + report_fatal_error("GetVr(): invalid type"); } void PPUTranslator::SetVr(u32 vr, Value* value) @@ -4435,7 +4435,7 @@ void PPUTranslator::SetFPRF(Value* value, bool set_cr) const bool is32 = value->getType()->isFloatTy() ? true : value->getType()->isDoubleTy() ? false : - throw std::logic_error("SetFPRF(): invalid value type"); + (report_fatal_error("SetFPRF(): invalid value type"), false); //const auto zero = ConstantFP::get(value->getType(), 0.0); //const auto is_nan = m_ir->CreateFCmpUNO(value, zero); diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 503a0aeceb..80bc0f8396 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -1154,7 +1154,7 @@ void spu_recompiler_base::branch(spu_thread& spu, void*, u8* rip) spu_runtime::g_tail_escape(&spu, func, rip); } -void spu_recompiler_base::old_interpreter(spu_thread& spu, void* ls, u8* rip) try +void spu_recompiler_base::old_interpreter(spu_thread& spu, void* ls, u8* rip) { // Select opcode table const auto& table = *( @@ -1178,11 +1178,6 @@ void spu_recompiler_base::old_interpreter(spu_thread& spu, void* ls, u8* rip) tr spu.pc += 4; } } -catch (const std::exception& e) -{ - spu_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); - spu_log.notice("\n%s", spu.dump()); -} spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point) { @@ -4608,19 +4603,7 @@ public: } // Execute recompiler function (TODO) - try - { - (this->*g_decoder.decode(op))({op}); - } - catch (const std::exception&) - { - std::string dump; - raw_string_ostream out(dump); - out << *module; // print IR - out.flush(); - spu_log.error("[0x%x] LLVM dump:\n%s", m_pos, dump); - throw; - } + (this->*g_decoder.decode(op))({op}); } // Finalize block with fallthrough if necessary @@ -4994,7 +4977,6 @@ public: } } - try { m_interp_bblock = nullptr; @@ -5142,15 +5124,6 @@ public: } } } - catch (const std::exception&) - { - std::string dump; - raw_string_ostream out(dump); - out << *module; // print IR - out.flush(); - spu_log.error("[0x%x] LLVM dump:\n%s", m_pos, dump); - throw; - } } if (last_itype != itype && g_cfg.core.spu_decoder != spu_decoder_type::llvm) diff --git a/rpcs3/Emu/GDB.cpp b/rpcs3/Emu/GDB.cpp index 1a92539d14..f32f4c7122 100644 --- a/rpcs3/Emu/GDB.cpp +++ b/rpcs3/Emu/GDB.cpp @@ -303,21 +303,13 @@ bool gdb_thread::read_cmd(gdb_cmd& out_cmd) { while (true) { - try + if (try_read_cmd(out_cmd)) { - if (try_read_cmd(out_cmd)) - { - ack(true); - return true; - } + ack(true); + return true; + } - ack(false); - } - catch (const std::runtime_error& e) - { - GDB.error("Error: %s", e.what()); - return false; - } + ack(false); } } @@ -866,7 +858,7 @@ void gdb_thread::operator()() Emu.Pause(); } - try { + { char hostbuf[32]; inet_ntop(client.sin_family, reinterpret_cast(&client.sin_addr), hostbuf, 32); GDB.success("Got connection to GDB debug server from %s:%d.", hostbuf, client.sin_port); @@ -905,16 +897,6 @@ void gdb_thread::operator()() } } } - catch (const std::runtime_error& e) - { - if (client_socket != -1) - { - closesocket(client_socket); - client_socket = -1; - } - - GDB.error("Error: %s", e.what()); - } } } diff --git a/rpcs3/Emu/RSX/Capture/rsx_replay.cpp b/rpcs3/Emu/RSX/Capture/rsx_replay.cpp index 007bfd79c4..e60096f4a8 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_replay.cpp +++ b/rpcs3/Emu/RSX/Capture/rsx_replay.cpp @@ -242,13 +242,6 @@ namespace rsx void rsx_replay_thread::operator()() { - try - { - on_task(); - } - catch (const std::exception& e) - { - rsx_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); - } + on_task(); } } diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index f2b82bf221..3364ecdcf5 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -2396,42 +2396,6 @@ public: namespace glsl { - class compilation_exception : public exception - { - public: - explicit compilation_exception(const std::string& what_arg) - { - m_what = "compilation failed: '" + what_arg + "'"; - } - }; - - class link_exception : public exception - { - public: - explicit link_exception(const std::string& what_arg) - { - m_what = "linkage failed: '" + what_arg + "'"; - } - }; - - class validation_exception : public exception - { - public: - explicit validation_exception(const std::string& what_arg) - { - m_what = "compilation failed: '" + what_arg + "'"; - } - }; - - class not_found_exception : public exception - { - public: - explicit not_found_exception(const std::string& what_arg) - { - m_what = what_arg + " not found."; - } - }; - class shader { public: @@ -2533,7 +2497,7 @@ public: error_msg = buf.get(); } - throw compilation_exception(error_msg); + rsx_log.fatal("Compilation failed: %s", error_msg); } return *this; @@ -2655,7 +2619,8 @@ public: } else { - throw not_found_exception(name); + rsx_log.fatal("%s not found.", name); + return -1; } } @@ -2663,7 +2628,8 @@ public: if (result < 0) { - throw not_found_exception(name); + rsx_log.fatal("%s not found.", name); + return result; } locations[name] = result; @@ -2749,7 +2715,7 @@ public: error_msg = buf.get(); } - throw link_exception(error_msg); + rsx_log.fatal("Linkage failed: %s", error_msg); } } diff --git a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp index 016f7151e6..4cbc65cbf3 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp @@ -42,7 +42,7 @@ namespace case rsx::index_array_type::u16: return GL_UNSIGNED_SHORT; case rsx::index_array_type::u32: return GL_UNSIGNED_INT; } - throw; + fmt::throw_exception("Invalid index array type (%u)", static_cast(type)); } struct vertex_input_state diff --git a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp index 8f9a911212..feb3000931 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace rsx { @@ -21,22 +22,65 @@ namespace rsx hex_color.erase(0, 1); } - unsigned long hexval; - const size_t len = hex_color.length(); + unsigned hexval = 0; + const auto len = hex_color.length(); - try + if (len != 6 && len != 8) { - if (len != 6 && len != 8) - { - fmt::throw_exception("wrong length: %d", len); - } - hexval = std::stoul(hex_color, nullptr, 16); - } - catch (const std::exception& e) - { - rsx_log.error("Overlays: tried to convert incompatible color code: '%s' exception: '%s'", hex_color, e.what()); + rsx_log.error("Incompatible color code: '%s' has wrong length: %d", hex_color, len); return color4f(0.0f, 0.0f, 0.0f, 0.0f); } + else + { + // auto&& [ptr, ec] = std::from_chars(hex_color.c_str(), hex_color.c_str() + len, &hexval, 16); + + // if (ptr != hex_color.c_str() + len || ec) + // { + // rsx_log.error("Overlays: tried to convert incompatible color code: '%s'", hex_color); + // return color4f(0.0f, 0.0f, 0.0f, 0.0f); + // } + for (u32 i = 0; i < len; i++) + { + hexval <<= 4; + + switch (char c = hex_color[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + hexval |= (c - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + hexval |= (c - 'a' + 10); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + hexval |= (c - 'A' + 10); + break; + default: + { + rsx_log.error("Overlays: invalid characters in color code: '%s'", hex_color); + return color4f(0.0f, 0.0f, 0.0f, 0.0f); + } + } + } + } const int r = (len == 8 ? (hexval >> 24) : (hexval >> 16)) & 0xff; const int g = (len == 8 ? (hexval >> 16) : (hexval >> 8)) & 0xff; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 5813de0c6a..28132ff242 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -442,7 +442,6 @@ namespace rsx void thread::operator()() { - try { // Wait for startup (TODO) while (m_rsx_thread_exiting) @@ -457,10 +456,6 @@ namespace rsx on_task(); } - catch (const std::exception& e) - { - rsx_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); - } on_exit(); } diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 3a3c32fe32..972b015a4f 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -52,7 +52,7 @@ namespace vk case rsx::index_array_type::u16: return VK_INDEX_TYPE_UINT16; } - throw; + fmt::throw_exception("Invalid index array type (%u)", static_cast(type)); } } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 3b060298a2..c0f12b8cb0 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -30,7 +30,7 @@ #include "../Crypto/unself.h" #include "../Crypto/unpkg.h" -#include +#include "util/yaml.hpp" #include "cereal/archives/binary.hpp" @@ -760,12 +760,23 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool m_title_id = title_id; } - try { Init(); // Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations) - YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string()); + YAML::Node games; + + if (fs::file f{fs::get_config_dir() + "/games.yml", fs::read + fs::create}) + { + auto [result, error] = yaml_load(f.to_string()); + + if (!error.empty()) + { + sys_log.error("Failed to load games.yml: %s", error); + } + + games = result; + } if (!games.IsMap()) { @@ -1462,12 +1473,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool } return game_boot_result::no_errors; } - catch (const std::exception& e) - { - sys_log.fatal("%s thrown: %s", typeid(e).name(), e.what()); - Stop(); - return game_boot_result::generic_error; - } } void Emulator::Run(bool start_playtime) diff --git a/rpcs3/cmake_modules/ConfigureCompiler.cmake b/rpcs3/cmake_modules/ConfigureCompiler.cmake index 93a264d68e..0fe5911b0a 100644 --- a/rpcs3/cmake_modules/ConfigureCompiler.cmake +++ b/rpcs3/cmake_modules/ConfigureCompiler.cmake @@ -2,7 +2,7 @@ if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1 /D _HAS_EXCEPTIONS=0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrtd.lib") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /DYNAMICBASE:NO /BASE:0x10000 /FIXED") @@ -23,7 +23,7 @@ else() CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) add_compile_options(-Wall) - add_compile_options(-fexceptions) + add_compile_options(-fno-exceptions) add_compile_options(-ftemplate-depth=1024) add_compile_options(-msse -msse2 -mcx16) add_compile_options(-fno-strict-aliasing) diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 95b4b86483..ac4022dd8a 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -87,6 +87,13 @@ NotUsing + + NotUsing + Sync + + + NotUsing + NotUsing diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 4aaa51b2de..b83eb77f4d 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -869,6 +869,15 @@ Utilities + + Utilities + + + Utilities + + + Utilities + Utilities diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index 5db3d7f7bc..9b4be29257 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -38,9 +38,11 @@ DYNAMIC_IMPORT("ntdll.dll", NtSetTimerResolution, NTSTATUS(ULONG DesiredResoluti #endif #include "Utilities/sysinfo.h" +#include "Utilities/Config.h" #include "rpcs3_version.h" #include "Emu/System.h" #include +#include inline std::string sstr(const QString& _in) { return _in.toStdString(); } @@ -213,49 +215,44 @@ QCoreApplication* createApplication(int& argc, char* argv[]) auto rounding_val = Qt::HighDpiScaleFactorRoundingPolicy::PassThrough; auto rounding_str = std::to_string(static_cast(rounding_val)); const auto i_rounding = find_arg(arg_rounding, argc, argv); + if (i_rounding) { const auto i_rounding_2 = (argc > (i_rounding + 1)) ? (i_rounding + 1) : 0; + if (i_rounding_2) { const auto arg_val = argv[i_rounding_2]; - try - { - const auto rounding_val_cli = std::stoi(arg_val); - if (rounding_val_cli >= static_cast(Qt::HighDpiScaleFactorRoundingPolicy::Unset) && rounding_val_cli <= static_cast(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough)) - { - rounding_val = static_cast(rounding_val_cli); - rounding_str = std::to_string(static_cast(rounding_val)); - } - else - { - throw std::exception(); - } - } - catch (const std::exception&) + const auto arg_len = std::strlen(arg_val); + s64 rounding_val_cli = 0; + + if (!cfg::try_to_int64(&rounding_val_cli, arg_val, static_cast(Qt::HighDpiScaleFactorRoundingPolicy::Unset), static_cast(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough))) { std::cout << "The value " << arg_val << " for " << arg_rounding << " is not allowed. Please use a valid value for Qt::HighDpiScaleFactorRoundingPolicy.\n"; } + else + { + rounding_val = static_cast(static_cast(rounding_val_cli)); + rounding_str = std::to_string(static_cast(rounding_val)); + } } } - try + { rounding_str = qEnvironmentVariable("QT_SCALE_FACTOR_ROUNDING_POLICY", rounding_str.c_str()).toStdString(); - const auto rounding_val_final = std::stoi(rounding_str); - if (rounding_val_final >= static_cast(Qt::HighDpiScaleFactorRoundingPolicy::Unset) && rounding_val_final <= static_cast(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough)) + + s64 rounding_val_final = 0; + + if (cfg::try_to_int64(&rounding_val_final, rounding_str, static_cast(Qt::HighDpiScaleFactorRoundingPolicy::Unset), static_cast(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough))) { - rounding_val = static_cast(rounding_val_final); + rounding_val = static_cast(static_cast(rounding_val_final)); rounding_str = std::to_string(static_cast(rounding_val)); } else { - throw std::exception(); + std::cout << "The value " << rounding_str << " for " << arg_rounding << " is not allowed. Please use a valid value for Qt::HighDpiScaleFactorRoundingPolicy.\n"; } } - catch (const std::exception&) - { - std::cout << "The value " << rounding_str << " for " << arg_rounding << " is not allowed. Please use a valid value for Qt::HighDpiScaleFactorRoundingPolicy.\n"; - } QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_val); } diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 2075781b41..5ff74a87a7 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -127,7 +127,6 @@ false ProgramDatabase 4577;4467;%(DisableSpecificWarnings) - Sync $(IntDir) MaxSpeed _WINDOWS;UNICODE;WIN32;WIN64;WITH_DISCORD_RPC;QT_NO_DEBUG;QT_OPENGL_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_QML_LIB;QT_NETWORK_LIB;QT_CORE_LIB;NDEBUG;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;%(PreprocessorDefinitions) @@ -180,7 +179,6 @@ false ProgramDatabase 4577;4467;%(DisableSpecificWarnings) - Sync $(IntDir) MaxSpeed _WINDOWS;UNICODE;WIN32;WIN64;WITH_DISCORD_RPC;QT_NO_DEBUG;QT_OPENGL_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_QML_LIB;QT_NETWORK_LIB;QT_CORE_LIB;NDEBUG;QT_WINEXTRAS_LIB;BRANCH=$(BRANCH);QT_CONCURRENT_LIB;%(PreprocessorDefinitions) @@ -233,7 +231,6 @@ false ProgramDatabase 4577;4467;%(DisableSpecificWarnings) - Sync $(IntDir) Disabled _WINDOWS;UNICODE;WIN32;WIN64;QT_OPENGL_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_QML_LIB;QT_NETWORK_LIB;QT_CORE_LIB;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;%(PreprocessorDefinitions) @@ -287,7 +284,6 @@ false ProgramDatabase 4577;4467;%(DisableSpecificWarnings) - Sync $(IntDir) Disabled _WINDOWS;UNICODE;WIN32;WIN64;QT_OPENGL_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_QML_LIB;QT_NETWORK_LIB;QT_CORE_LIB;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;%(PreprocessorDefinitions) diff --git a/rpcs3/rpcs3qt/cheat_manager.cpp b/rpcs3/rpcs3qt/cheat_manager.cpp index 857e112c67..2b6cc9f701 100644 --- a/rpcs3/rpcs3qt/cheat_manager.cpp +++ b/rpcs3/rpcs3qt/cheat_manager.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "cheat_manager.h" #include "Emu/System.h" @@ -19,6 +17,7 @@ #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/PPUFunction.h" +#include "util/yaml.hpp" #include "Utilities/StrUtil.h" LOG_CHANNEL(log_cheat, "Cheat"); @@ -110,9 +109,14 @@ std::string cheat_info::to_str() const cheat_engine::cheat_engine() { - try + if (fs::file cheat_file{fs::get_config_dir() + cheats_filename, fs::read + fs::create}) { - YAML::Node yml_cheats = YAML::Load(fs::file{fs::get_config_dir() + cheats_filename, fs::read + fs::create}.to_string()); + auto [yml_cheats, error] = yaml_load(cheat_file.to_string()); + + if (!error.empty()) + { + log_cheat.error("Error parsing %s: %s", cheats_filename, error); + } for (const auto& yml_cheat : yml_cheats) { @@ -127,9 +131,9 @@ cheat_engine::cheat_engine() } } } - catch (YAML::Exception& e) + else { - log_cheat.error("Error parsing %s\n%s", cheats_filename, e.what()); + log_cheat.error("Error loading %s", cheats_filename); } } diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index eaeaf8edf2..62bb61c0dd 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -18,6 +18,7 @@ #include "Loader/PSF.h" #include "Utilities/types.h" #include "Utilities/lockless.h" +#include "util/yaml.hpp" #include #include @@ -543,24 +544,23 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) auto get_games = []() -> YAML::Node { - try - { - fs::file games(fs::get_config_dir() + "/games.yml", fs::read + fs::create); + fs::file games(fs::get_config_dir() + "/games.yml", fs::read + fs::create); - if (games) + if (games) + { + auto [result, error] = yaml_load(games.to_string()); + + if (!error.empty()) { - return YAML::Load(games.to_string()); - } - else - { - game_list_log.error("Failed to load games.yml, check permissions."); + game_list_log.error("Failed to load games.yml: %s", error); return {}; } + + return result; } - catch (...) + else { - // YAML exception aren't very useful so just ignore them - game_list_log.fatal("Failed to parse games.yml"); + game_list_log.error("Failed to load games.yml, check permissions."); return {}; } @@ -616,7 +616,6 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) { const Localized thread_localized; - try { const std::string sfo_dir = Emulator::GetSfoDirFromGamePath(dir, Emu.GetUsr()); const fs::file sfo_file(sfo_dir + "/PARAM.SFO"); @@ -724,11 +723,6 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) games.push(std::make_shared(gui_game_info{game, qt_cat, compat, icon, pxmap, hasCustomConfig, hasCustomPadConfig})); } - catch (const std::exception& e) - { - game_list_log.fatal("Failed to update game list at %s\n%s thrown: %s", dir, typeid(e).name(), e.what()); - return; - } }); for (auto&& g : games.pop_all()) @@ -744,29 +738,37 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) for (const auto& other : m_game_data) { // The patch is game data and must have the same serial and an app version + static constexpr auto version_is_bigger = [](const std::string& v0, const std::string& v1, const std::string& serial, bool is_fw) + { + std::add_pointer_t ev0, ev1; + const double ver0 = std::strtod(v0.c_str(), &ev0); + const double ver1 = std::strtod(v1.c_str(), &ev1); + + if (v0.c_str() + v0.size() == ev0 && v1.c_str() + v1.size() == ev1) + { + return ver0 > ver1; + } + + game_list_log.error("Failed to update the displayed %s numbers for title ID %s\n'%s'-'%s'", is_fw ? "firmware version" : "version", serial, v0, v1); + return false; + }; + if (entry->info.serial == other->info.serial && other->info.category == "GD" && other->info.app_ver != cat_unknown_localized) { - try + // Update the app version if it's higher than the disc's version (old games may not have an app version) + if (entry->info.app_ver == cat_unknown_localized || version_is_bigger(other->info.app_ver, entry->info.app_ver, entry->info.serial, true)) { - // Update the app version if it's higher than the disc's version (old games may not have an app version) - if (entry->info.app_ver == cat_unknown_localized || std::stod(other->info.app_ver) > std::stod(entry->info.app_ver)) - { - entry->info.app_ver = other->info.app_ver; - } - // Update the firmware version if possible and if it's higher than the disc's version - if (other->info.fw != cat_unknown_localized && std::stod(other->info.fw) > std::stod(entry->info.fw)) - { - entry->info.fw = other->info.fw; - } - // Update the parental level if possible and if it's higher than the disc's level - if (other->info.parental_lvl != 0 && other->info.parental_lvl > entry->info.parental_lvl) - { - entry->info.parental_lvl = other->info.parental_lvl; - } + entry->info.app_ver = other->info.app_ver; } - catch (const std::exception& e) + // Update the firmware version if possible and if it's higher than the disc's version + if (other->info.fw != cat_unknown_localized && version_is_bigger(other->info.fw, entry->info.fw, entry->info.serial, false)) { - game_list_log.error("Failed to update the displayed version numbers for title ID %s\n%s thrown: %s", entry->info.serial, typeid(e).name(), e.what()); + entry->info.fw = other->info.fw; + } + // Update the parental level if possible and if it's higher than the disc's level + if (other->info.parental_lvl != 0 && other->info.parental_lvl > entry->info.parental_lvl) + { + entry->info.parental_lvl = other->info.parental_lvl; } } } diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index a938eb6c1d..63644596b5 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -147,7 +147,7 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) while (value.length() < 32) value = "0" + value; const auto first_brk = reg.find('['); - try + // TODO: handle invalid conversions { if (first_brk != umax) { @@ -182,9 +182,6 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) return; } } - catch (std::invalid_argument&) //if any of the stoull conversion fail - { - } } else { @@ -192,7 +189,7 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) while (value.length() < 32) value = "0" + value; const auto first_brk = reg.find('['); - try + // TODO: handle invalid conversions { if (first_brk != umax) { @@ -207,9 +204,6 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) } } } - catch (std::invalid_argument&) - { - } } QMessageBox::critical(this, tr("Error"), tr("This value could not be converted.\nNo changes were made.")); } diff --git a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp index 9b0fc70fc2..98db2bc8b2 100644 --- a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp @@ -710,15 +710,12 @@ void trophy_manager_dialog::StartTrophyLoadThreads() { const std::string dir_name = sstr(folder_list.value(i)); gui_log.trace("Loading trophy dir: %s", dir_name); - try - { - LoadTrophyFolderToDB(dir_name); - } - catch (const std::exception& e) + + if (!LoadTrophyFolderToDB(dir_name)) { // TODO: Add error checks & throws to LoadTrophyFolderToDB so that they can be caught here. // Also add a way of showing the number of corrupted/invalid folders in UI somewhere. - gui_log.error("Exception occurred while parsing folder %s for trophies: %s", dir_name, e.what()); + gui_log.error("Error occurred while parsing folder %s for trophies.", dir_name); } })); diff --git a/rpcs3/util/cereal.cpp b/rpcs3/util/cereal.cpp new file mode 100644 index 0000000000..02598ba918 --- /dev/null +++ b/rpcs3/util/cereal.cpp @@ -0,0 +1,10 @@ +#include +#include "Utilities/Thread.h" + +namespace cereal +{ + [[noreturn]] void throw_exception(const std::string& err) + { + report_fatal_error(err); + } +} diff --git a/rpcs3/util/logs.cpp b/rpcs3/util/logs.cpp index d7e4f6009e..8cc7bc1550 100644 --- a/rpcs3/util/logs.cpp +++ b/rpcs3/util/logs.cpp @@ -307,8 +307,8 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, ...) co const u64 stamp = get_stamp(); // Get text, extract va_args - thread_local std::string text; - thread_local std::vector args; + /*constinit thread_local*/ std::string text; + /*constinit thread_local*/ std::basic_string args; static constexpr fmt_type_info empty_sup{}; @@ -316,7 +316,7 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, ...) co for (auto v = sup; v && v->fmt_string; v++) args_count++; - text.clear(); + text.reserve(50000); args.resize(args_count); va_list c_args; @@ -589,7 +589,8 @@ logs::file_listener::file_listener(const std::string& path, u64 max_size) void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::string& prefix, const std::string& _text) { - thread_local std::string text; + /*constinit thread_local*/ std::string text; + text.reserve(50000); // Used character: U+00B7 (Middle Dot) switch (msg.sev) diff --git a/rpcs3/util/yaml.cpp b/rpcs3/util/yaml.cpp new file mode 100644 index 0000000000..71cfde00b7 --- /dev/null +++ b/rpcs3/util/yaml.cpp @@ -0,0 +1,17 @@ +#include "util/yaml.hpp" + +std::pair yaml_load(const std::string& from) +{ + YAML::Node result; + + try + { + result = YAML::Load(from); + } + catch(const std::exception& e) + { + return{YAML::Node(), std::string("YAML exception:\n") + e.what()}; + } + + return{result, ""}; +} diff --git a/rpcs3/util/yaml.hpp b/rpcs3/util/yaml.hpp new file mode 100644 index 0000000000..e36a1744cd --- /dev/null +++ b/rpcs3/util/yaml.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 0) +#include "yaml-cpp/yaml.h" +#pragma warning(pop) +#else +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include "yaml-cpp/yaml.h" +#pragma GCC diagnostic pop +#endif + +// Load from string and consume exception +std::pair yaml_load(const std::string& from); diff --git a/rpcs3_default.props b/rpcs3_default.props index 14ebef99eb..4b672af78d 100644 --- a/rpcs3_default.props +++ b/rpcs3_default.props @@ -13,10 +13,11 @@ true - PUGIXML_HEADER_ONLY;_ENABLE_EXTENDED_ALIGNED_STORAGE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;%(PreprocessorDefinitions) + PUGIXML_HEADER_ONLY;_ENABLE_EXTENDED_ALIGNED_STORAGE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions) true Level3 false + false true NotUsing /Zc:throwingNew %(AdditionalOptions)