From 111c1ab531eb565dabe7f3ca6f19a9cfaedf5880 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 11 Oct 2023 10:20:05 +0200 Subject: [PATCH] AchievementManager: Don't store pointer to rc_runtime_event_t in lambda. Scope issue in the event callback from `rc_runtime_do_frame()`. The pointer points to a variable on the stack from inside `rc_runtime_do_frame()`, so that's a race condition between the thread calling `rc_runtime_do_frame()` and the event queue thread. --- Source/Core/Core/AchievementManager.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index cbc07a7c86..fe955e6053 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -1088,15 +1088,15 @@ AchievementManager::PingRichPresence(const RichPresence& rich_presence) void AchievementManager::HandleAchievementTriggeredEvent(const rc_runtime_event_t* runtime_event) { - auto it = m_unlock_map.find(runtime_event->id); + const auto event_id = runtime_event->id; + auto it = m_unlock_map.find(event_id); if (it == m_unlock_map.end()) { - ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid achievement triggered event with id {}.", - runtime_event->id); + ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid achievement triggered event with id {}.", event_id); return; } it->second.session_unlock_count++; - m_queue.EmplaceItem([this, runtime_event] { AwardAchievement(runtime_event->id); }); + m_queue.EmplaceItem([this, event_id] { AwardAchievement(event_id); }); AchievementId game_data_index = it->second.game_data_index; OSD::AddMessage(fmt::format("Unlocked: {} ({})", m_game_data.achievements[game_data_index].title, m_game_data.achievements[game_data_index].points), @@ -1115,7 +1115,7 @@ void AchievementManager::HandleAchievementTriggeredEvent(const rc_runtime_event_ fmt::format("Congratulations! {} has completed {}", m_display_name, m_game_data.title), OSD::Duration::VERY_LONG, OSD::Color::CYAN); } - ActivateDeactivateAchievement(runtime_event->id, Config::Get(Config::RA_ACHIEVEMENTS_ENABLED), + ActivateDeactivateAchievement(event_id, Config::Get(Config::RA_ACHIEVEMENTS_ENABLED), Config::Get(Config::RA_UNOFFICIAL_ENABLED), Config::Get(Config::RA_ENCORE_ENABLED)); } @@ -1175,15 +1175,16 @@ void AchievementManager::HandleLeaderboardCanceledEvent(const rc_runtime_event_t void AchievementManager::HandleLeaderboardTriggeredEvent(const rc_runtime_event_t* runtime_event) { - m_queue.EmplaceItem( - [this, runtime_event] { SubmitLeaderboard(runtime_event->id, runtime_event->value); }); + const auto event_id = runtime_event->id; + const auto event_value = runtime_event->value; + m_queue.EmplaceItem([this, event_id, event_value] { SubmitLeaderboard(event_id, event_value); }); for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++) { - if (m_game_data.leaderboards[ix].id == runtime_event->id) + if (m_game_data.leaderboards[ix].id == event_id) { FormattedValue value{}; - rc_runtime_format_lboard_value(value.data(), static_cast(value.size()), - runtime_event->value, m_game_data.leaderboards[ix].format); + rc_runtime_format_lboard_value(value.data(), static_cast(value.size()), event_value, + m_game_data.leaderboards[ix].format); if (std::find(value.begin(), value.end(), '\0') == value.end()) { OSD::AddMessage(fmt::format("Scored {} on leaderboard: {}", @@ -1200,7 +1201,7 @@ void AchievementManager::HandleLeaderboardTriggeredEvent(const rc_runtime_event_ return; } } - ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid leaderboard triggered event with id {}.", runtime_event->id); + ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid leaderboard triggered event with id {}.", event_id); } // Every RetroAchievements API call, with only a partial exception for fetch_image, follows