From 1c3eedcf28a1e8c964092624b99744d05a3aa1a8 Mon Sep 17 00:00:00 2001 From: David Racine Date: Mon, 1 Jun 2026 13:04:41 -0400 Subject: [PATCH 1/2] Fixed crash and memory leaks at shutdown --- soh/soh/OTRGlobals.cpp | 43 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 0c889ad5bfc..251d7158768 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -139,16 +139,16 @@ const float imguiScaleOptionToValue[4] = { 0.75f, 1.0f, 1.5f, 2.0f }; bool SoH_HandleConfigDrop(char* filePath); -OTRGlobals* OTRGlobals::Instance; -SaveManager* SaveManager::Instance; -CustomMessageManager* CustomMessageManager::Instance; -ItemTableManager* ItemTableManager::Instance; -GameInteractor* GameInteractor::Instance; -AudioCollection* AudioCollection::Instance; -SpeechSynthesizer* SpeechSynthesizer::Instance; -CrowdControl* CrowdControl::Instance; -Sail* Sail::Instance; -Anchor* Anchor::Instance; +OTRGlobals* OTRGlobals::Instance = nullptr; +SaveManager* SaveManager::Instance = nullptr; +CustomMessageManager* CustomMessageManager::Instance = nullptr; +ItemTableManager* ItemTableManager::Instance = nullptr; +GameInteractor* GameInteractor::Instance = nullptr; +AudioCollection* AudioCollection::Instance = nullptr; +SpeechSynthesizer* SpeechSynthesizer::Instance = nullptr; +CrowdControl* CrowdControl::Instance = nullptr; +Sail* Sail::Instance = nullptr; +Anchor* Anchor::Instance = nullptr; extern "C" char** cameraStrings; @@ -1568,7 +1568,16 @@ extern "C" void DeinitOTR() { SohGui::Destroy(); sohFast3dWindow = nullptr; - OTRGlobals::Instance->context = nullptr; + delete SaveManager::Instance; + SaveManager::Instance = nullptr; + delete GameInteractor::Instance; + GameInteractor::Instance = nullptr; + delete ItemTableManager::Instance; + ItemTableManager::Instance = nullptr; + delete CustomMessageManager::Instance; + CustomMessageManager::Instance = nullptr; + delete OTRGlobals::Instance; + OTRGlobals::Instance = nullptr; } #ifdef _WIN32 @@ -2120,11 +2129,15 @@ extern "C" void OTRControllerCallback(uint8_t rumble) { Ship::Context::GetRawInstance()->GetControlDeck()->GetControllerByPort(0)->GetLED()->SetLEDColor( GetColorForControllerLED()); - static std::shared_ptr controllerConfigWindow = nullptr; + static std::weak_ptr sControllerConfigWindow{}; + auto controllerConfigWindow = sControllerConfigWindow.lock(); if (controllerConfigWindow == nullptr) { - controllerConfigWindow = std::dynamic_pointer_cast( - std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetWindow()->GetGui()) - ->GetGuiWindow("Controller Configuration")); + auto gui = std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetWindow()->GetGui()); + if (gui != nullptr) + controllerConfigWindow = + std::dynamic_pointer_cast(gui->GetGuiWindow("Controller Configuration")); + + sControllerConfigWindow = controllerConfigWindow; } else if (controllerConfigWindow->TestingRumble()) { return; } From e7334d6d6ed52f868142a409cc2ee9cbb46d63ff Mon Sep 17 00:00:00 2001 From: David Racine Date: Tue, 23 Jun 2026 10:28:57 -0400 Subject: [PATCH 2/2] fix(crash): null-check controllerConfigWindow before TestingRumble Restores the guard from the original shutdown-crash fix that was dropped when the branch was recreated: on the first OTRControllerCallback the window is created in the if-branch, so the old else-if could dereference a null controllerConfigWindow. Co-Authored-By: Claude Opus 4.8 --- soh/soh/OTRGlobals.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 3da972ba5a7..af966441994 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2195,7 +2195,9 @@ extern "C" void OTRControllerCallback(uint8_t rumble) { std::dynamic_pointer_cast(gui->GetGuiWindow("Controller Configuration")); sControllerConfigWindow = controllerConfigWindow; - } else if (controllerConfigWindow->TestingRumble()) { + } + + if (controllerConfigWindow != nullptr && controllerConfigWindow->TestingRumble()) { return; }