From 7d3774a732a0cecd6655499eec529e86567f3c27 Mon Sep 17 00:00:00 2001 From: dgelessus Date: Thu, 29 Jun 2023 22:03:53 +0200 Subject: [PATCH] Unload all keys of all pages before deleting them (ported from H-uru/Plasma@04d0ac94ea25fc937931b8f4f546220ddf1cc27c) --- .../Plasma/PubUtilLib/plResMgr/plResManager.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp b/Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp index cb30f6cb..bd7edfd6 100644 --- a/Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp +++ b/Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp @@ -219,14 +219,20 @@ void plResManager::IShutdown() // Shut down the registry (finally!) ILockPages(); - PageSet::const_iterator it; - for (it = fAllPages.begin(); it != fAllPages.end(); it++) + // Unload all keys before actually deleting the pages. + // When a key's refcount drops to zero, IKeyUnreffed looks up the key's page. + // If the page is already deleted at that point, this causes a use after free and potential crash. + for (PageSet::const_iterator it = fAllPages.begin(); it != fAllPages.end(); it++) { + (*it)->UnloadKeys(); + } + fLoadedPages.clear(); + fLastFoundPage = nil; + for (PageSet::const_iterator it = fAllPages.begin(); it != fAllPages.end(); it++) { delete *it; + } fAllPages.clear(); - fLoadedPages.clear(); IUnlockPages(); - fLastFoundPage = nil; // Now, kill off the Dispatcher hsRefCnt_SafeUnRef(fDispatch);