From eb5dababc928dbf36a708f2ca76a54612ceb9506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Sat, 16 Aug 2025 00:07:07 +0200 Subject: [PATCH] Fix a crash when closing windows would open other windows (#24972) This could happen when trying to open a ride, which does not have entrance or exit, from the ride list window. The `OnClose` handler would want to open a window for placing said elements causing invalidation of the window list. https://github.com/OpenRCT2/OpenRCT2/blob/20ac77904b0586c66af5a764035c8141ba3e9081/src/openrct2-ui/windows/RideConstruction.cpp#L324 --- distribution/changelog.txt | 1 + src/openrct2-ui/WindowManager.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index d67ca1e908..39312726f7 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -20,6 +20,7 @@ - Fix: [#24955] Hybrid Zero G Rolls do not fully block metal supports. - Fix: [#24958] Android: fix crash when device is offline. - Fix: [#24961] Queues with corner connections set with the tile inspector draw incorrect sprites. +- Fix: [#24972] Fix crash when closing windows would open other windows. 0.4.25 (2025-08-03) ------------------------------------------------------------------------ diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp index 0f01bcb7fa..00280fff98 100644 --- a/src/openrct2-ui/WindowManager.cpp +++ b/src/openrct2-ui/WindowManager.cpp @@ -981,6 +981,10 @@ public: template void CloseByCondition(TPred pred, uint32_t flags = WindowCloseFlags::None) { + // Collect windows to close first to avoid iterator invalidation + // when Close() might trigger window creation via OnClose() + std::vector windowsToClose; + for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); ++it) { auto& wnd = *(*it); @@ -989,13 +993,22 @@ public: if (pred(&wnd)) { - Close(wnd); + windowsToClose.push_back(&wnd); if (flags & WindowCloseFlags::CloseSingle) { - return; + break; } } } + + // Now close the collected windows + for (auto* wnd : windowsToClose) + { + if (!(wnd->flags & WF_DEAD)) + { + Close(*wnd); + } + } } /**