From 95e2064099454f0c3d972674d6ce1fa7551ce77f Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 7 Jul 2024 11:43:43 +0200 Subject: [PATCH] Fix AchievementManager::SetBackgroundExecutionAllowed crash We mustn't use m_system when it is nullptr. This was causing Dolphin to crash on Android whenever an activity was recreated or resumed while emulation is running, which is super common. --- Source/Core/Core/AchievementManager.cpp | 19 +++++++++++++------ Source/Core/Core/AchievementManager.h | 3 ++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 544ec36afc..8e05ab0271 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -166,7 +166,12 @@ bool AchievementManager::IsGameLoaded() const void AchievementManager::SetBackgroundExecutionAllowed(bool allowed) { m_background_execution_allowed = allowed; - if (allowed && Core::GetState(*AchievementManager::GetInstance().m_system) == Core::State::Paused) + + Core::System* system = m_system.load(std::memory_order_acquire); + if (!system) + return; + + if (allowed && Core::GetState(*system) == Core::State::Paused) DoIdle(); } @@ -241,7 +246,8 @@ void AchievementManager::DoFrame() std::lock_guard lg{m_lock}; rc_client_do_frame(m_client); } - if (!m_system) + Core::System* system = m_system.load(std::memory_order_acquire); + if (!system) return; auto current_time = std::chrono::steady_clock::now(); if (current_time - m_last_rp_time > std::chrono::seconds{10}) @@ -279,7 +285,8 @@ void AchievementManager::DoIdle() Common::SleepCurrentThread(1000); { std::lock_guard lg{m_lock}; - if (!m_system || Core::GetState(*m_system) != Core::State::Paused) + Core::System* system = m_system.load(std::memory_order_acquire); + if (!system || Core::GetState(*system) != Core::State::Paused) return; if (!m_background_execution_allowed) return; @@ -290,7 +297,7 @@ void AchievementManager::DoIdle() // needs to be on host or CPU thread to access memory. Core::QueueHostJob([this](Core::System& system) { std::lock_guard lg{m_lock}; - if (!m_system || Core::GetState(*m_system) != Core::State::Paused) + if (Core::GetState(system) != Core::State::Paused) return; if (!m_background_execution_allowed) return; @@ -487,7 +494,7 @@ void AchievementManager::CloseGame() m_queue.Cancel(); m_image_queue.Cancel(); rc_client_unload_game(m_client); - m_system = nullptr; + m_system.store(nullptr, std::memory_order_release); if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)) Discord::UpdateDiscordPresence(); INFO_LOG_FMT(ACHIEVEMENTS, "Game closed."); @@ -747,7 +754,7 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, rc_client_set_read_memory_function(instance.m_client, MemoryPeeker); instance.m_display_welcome_message = true; instance.FetchGameBadges(); - instance.m_system = &Core::System::GetInstance(); + instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release); instance.m_update_callback({.all = true}); // Set this to a value that will immediately trigger RP instance.m_last_rp_time = std::chrono::steady_clock::now() - std::chrono::minutes{2}; diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 3996003040..1b9c828661 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -5,6 +5,7 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include +#include #include #include #include @@ -189,7 +190,7 @@ private: rc_runtime_t m_runtime{}; rc_client_t* m_client{}; - Core::System* m_system{}; + std::atomic m_system{}; bool m_is_runtime_initialized = false; UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume;