reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit bf27e9c6324f6ce2b32e3e19a8fe65d8d8aa9b7b
parent dfaf79ee2069c4f5c49761253f9102e8446f47f4
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Sat, 22 Sep 2018 20:56:36 -0400

fix use-after-free when closing modeless UI windows [p=2037784]

It was caused by a lambda attempting to access a captured value after having destroyed its parent object (thus also all captures).

Diffstat:
Msrc/dialog.cpp | 12------------
Msrc/dialog.hpp | 18++++++------------
Msrc/reapack.cpp | 52++++++++++++++++++----------------------------------
Msrc/reapack.hpp | 10++++++----
4 files changed, 30 insertions(+), 62 deletions(-)

diff --git a/src/dialog.cpp b/src/dialog.cpp @@ -166,18 +166,6 @@ INT_PTR Dialog::init(REAPER_PLUGIN_HINSTANCE inst, HWND parent, Modality mode) return false; // makes MSVC happy. } -void Dialog::Destroy(Dialog *dlg) -{ - delete dlg; -} - -void Dialog::DestroyAll() -{ - const auto map = s_instances; // make an immutable copy - for(Dialog *dlg : map | boost::adaptors::map_values) - Destroy(dlg); -} - void Dialog::setVisible(const bool visible, HWND handle) { if(!handle) diff --git a/src/dialog.hpp b/src/dialog.hpp @@ -22,6 +22,7 @@ #include <functional> #include <map> +#include <memory> #include <set> #include <vector> @@ -52,27 +53,20 @@ public: }; template<class T, class... Args> - static T *Create(REAPER_PLUGIN_HINSTANCE instance, HWND parent, Args&&... args) + static std::unique_ptr<T> Create(REAPER_PLUGIN_HINSTANCE instance, HWND parent, Args&&... args) { - Dialog *dlg = new T(args...); + auto dlg = std::make_unique<T>(args...); dlg->init(instance, parent, Dialog::Modeless); - return static_cast<T *>(dlg); + return dlg; } template<class T, class... Args> - static INT_PTR Show(REAPER_PLUGIN_HINSTANCE i, HWND parent, Args&&... args) + static INT_PTR Show(REAPER_PLUGIN_HINSTANCE instance, HWND parent, Args&&... args) { - Dialog *dlg = new T(args...); - INT_PTR ret = dlg->init(i, parent, Dialog::Modal); - Destroy(dlg); - - return ret; + return std::make_unique<T>(args...)->init(instance, parent, Dialog::Modal); } - static void Destroy(Dialog *); - static void DestroyAll(); - INT_PTR init(REAPER_PLUGIN_HINSTANCE, HWND, const Modality); REAPER_PLUGIN_HINSTANCE instance() const { return m_instance; } diff --git a/src/reapack.cpp b/src/reapack.cpp @@ -19,7 +19,6 @@ #include "about.hpp" #include "api.hpp" -#include "browser.hpp" #include "config.hpp" #include "download.hpp" #include "errors.hpp" @@ -80,8 +79,7 @@ Path ReaPack::resourcePath() ReaPack::ReaPack(REAPER_PLUGIN_HINSTANCE instance, HWND mainWindow) : m_instance(instance), m_mainWindow(mainWindow), - m_useRootPath(resourcePath()), m_config(Path::CONFIG.prependRoot()), - m_tx{}, m_about{}, m_browser{}, m_manager{}, m_progress{} + m_useRootPath(resourcePath()), m_config(Path::CONFIG.prependRoot()), m_tx{} { assert(!s_instance); s_instance = this; @@ -104,7 +102,6 @@ ReaPack::ReaPack(REAPER_PLUGIN_HINSTANCE instance, HWND mainWindow) ReaPack::~ReaPack() { - Dialog::DestroyAll(); DownloadContext::GlobalCleanup(); s_instance = nullptr; @@ -210,11 +207,7 @@ void ReaPack::manageRemotes() m_manager = Dialog::Create<Manager>(m_instance, m_mainWindow); m_manager->show(); - - m_manager->setCloseHandler([=] (INT_PTR) { - Dialog::Destroy(m_manager); - m_manager = nullptr; - }); + m_manager->setCloseHandler([=](INT_PTR) { m_manager.reset(); }); } Remote ReaPack::remote(const string &name) const @@ -247,35 +240,27 @@ void ReaPack::aboutSelf() About *ReaPack::about(const bool instantiate) { if(m_about) - return m_about; + return m_about.get(); else if(!instantiate) return nullptr; m_about = Dialog::Create<About>(m_instance, m_mainWindow); + m_about->setCloseHandler([=](INT_PTR) { m_about.reset(); }); - m_about->setCloseHandler([=] (INT_PTR) { - Dialog::Destroy(m_about); - m_about = nullptr; - }); - - return m_about; + return m_about.get(); } Browser *ReaPack::browsePackages() { - if(m_browser) { + if(m_browser) m_browser->setFocus(); - return m_browser; + else { + m_browser = Dialog::Create<Browser>(m_instance, m_mainWindow); + m_browser->refresh(); + m_browser->setCloseHandler([=](INT_PTR) { m_browser.reset(); }); } - m_browser = Dialog::Create<Browser>(m_instance, m_mainWindow); - m_browser->refresh(); - m_browser->setCloseHandler([=] (INT_PTR) { - Dialog::Destroy(m_browser); - m_browser = nullptr; - }); - - return m_browser; + return m_browser.get(); } Transaction *ReaPack::setupTransaction() @@ -304,22 +289,21 @@ Transaction *ReaPack::setupTransaction() m_progress = Dialog::Create<Progress>(m_instance, m_mainWindow, m_tx->threadPool()); m_tx->onFinish([=] { - Dialog::Destroy(m_progress); - m_progress = nullptr; + m_progress.reset(); if(!m_tx->isCancelled() && !m_tx->receipt()->empty()) { - LockDialog managerLock(m_manager); - LockDialog browserLock(m_browser); + LockDialog managerLock(m_manager.get()); + LockDialog browserLock(m_browser.get()); Dialog::Show<Report>(m_instance, m_mainWindow, m_tx->receipt()); } }); m_tx->setObsoleteHandler([=] (vector<Registry::Entry> &entries) { - LockDialog aboutLock(m_about); - LockDialog browserLock(m_browser); - LockDialog managerLock(m_manager); - LockDialog progressLock(m_progress); + LockDialog aboutLock(m_about.get()); + LockDialog browserLock(m_browser.get()); + LockDialog managerLock(m_manager.get()); + LockDialog progressLock(m_progress.get()); return Dialog::Show<ObsoleteQuery>(m_instance, m_mainWindow, &entries, &config()->install.promptObsolete) == IDOK; diff --git a/src/reapack.hpp b/src/reapack.hpp @@ -20,6 +20,8 @@ #include "action.hpp" #include "api.hpp" +#include "browser.hpp" +#include "browser_entry.hpp" #include "config.hpp" #include "path.hpp" @@ -86,10 +88,10 @@ private: std::list<APIDef> m_api; Transaction *m_tx; - About *m_about; - Browser *m_browser; - Manager *m_manager; - Progress *m_progress; + std::unique_ptr<About> m_about; + std::unique_ptr<Browser> m_browser; + std::unique_ptr<Manager> m_manager; + std::unique_ptr<Progress> m_progress; }; #endif