From c342d5ca44ec4ecbd39b595d458ea58214b5d871 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 8 Jul 2024 23:06:28 +0200 Subject: [PATCH] memory: do not release pointers after emitting a signal A signal called is allowed to free ourselves, in which case we're not allowed to use this anymore. Only perform the housekeeping of removing stale events before emit, and in registerListener. --- src/signal/Signal.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/signal/Signal.cpp b/src/signal/Signal.cpp index 698d16a..3442fe7 100644 --- a/src/signal/Signal.cpp +++ b/src/signal/Signal.cpp @@ -9,14 +9,10 @@ using namespace Hyprutils::Memory; #define WP CWeakPointer void Hyprutils::Signal::CSignal::emit(std::any data) { - bool dirty = false; - std::vector> listeners; for (auto& l : m_vListeners) { - if (l.expired()) { - dirty = true; + if (l.expired()) continue; - } listeners.emplace_back(l.lock()); } @@ -29,10 +25,9 @@ void Hyprutils::Signal::CSignal::emit(std::any data) { for (auto& l : listeners) { // if there is only one lock, it means the event is only held by the listeners // vector and was removed during our iteration - if (l.strongRef() == 1) { - dirty = true; + if (l.strongRef() == 1) continue; - } + l->emit(data); } @@ -43,13 +38,17 @@ void Hyprutils::Signal::CSignal::emit(std::any data) { // release SPs listeners.clear(); - if (dirty) - std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); + // we cannot release any expired refs here as one of the listeners could've removed this object and + // as such we'd be doing a UAF } CHyprSignalListener Hyprutils::Signal::CSignal::registerListener(std::function handler) { CHyprSignalListener listener = makeShared(handler); m_vListeners.emplace_back(listener); + + // housekeeping: remove any stale listeners + std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); + return listener; }