diff --git a/Sources/Plasma/PubUtilLib/plResMgr/plRegistryKeyList.cpp b/Sources/Plasma/PubUtilLib/plResMgr/plRegistryKeyList.cpp index 58fcc8c2..8ddcb962 100644 --- a/Sources/Plasma/PubUtilLib/plResMgr/plRegistryKeyList.cpp +++ b/Sources/Plasma/PubUtilLib/plResMgr/plRegistryKeyList.cpp @@ -59,8 +59,10 @@ plRegistryKeyList::~plRegistryKeyList() for (int i = 0; i < fStaticKeys.size(); i++) { plKeyImp* keyImp = fStaticKeys[i]; - if (!keyImp->ObjectIsLoaded()) + if (keyImp && !keyImp->ObjectIsLoaded()) { + fStaticKeys[i] = nullptr; delete keyImp; + } } } diff --git a/Sources/Plasma/PubUtilLib/plResMgr/plRegistryNode.cpp b/Sources/Plasma/PubUtilLib/plResMgr/plRegistryNode.cpp index 8c8954b5..c0eacdcb 100644 --- a/Sources/Plasma/PubUtilLib/plResMgr/plRegistryNode.cpp +++ b/Sources/Plasma/PubUtilLib/plResMgr/plRegistryNode.cpp @@ -203,6 +203,7 @@ void plRegistryPageNode::UnloadKeys() for (; it != fKeyLists.end(); it++) { plRegistryKeyList* keyList = it->second; + it->second = nullptr; delete keyList; } fKeyLists.clear(); 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);