mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-11-17 00:15:58 +01:00
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.
This commit is contained in:
parent
a8c3a13570
commit
c342d5ca44
1 changed files with 9 additions and 10 deletions
|
@ -9,14 +9,10 @@ using namespace Hyprutils::Memory;
|
||||||
#define WP CWeakPointer
|
#define WP CWeakPointer
|
||||||
|
|
||||||
void Hyprutils::Signal::CSignal::emit(std::any data) {
|
void Hyprutils::Signal::CSignal::emit(std::any data) {
|
||||||
bool dirty = false;
|
|
||||||
|
|
||||||
std::vector<SP<CSignalListener>> listeners;
|
std::vector<SP<CSignalListener>> listeners;
|
||||||
for (auto& l : m_vListeners) {
|
for (auto& l : m_vListeners) {
|
||||||
if (l.expired()) {
|
if (l.expired())
|
||||||
dirty = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
listeners.emplace_back(l.lock());
|
listeners.emplace_back(l.lock());
|
||||||
}
|
}
|
||||||
|
@ -29,10 +25,9 @@ void Hyprutils::Signal::CSignal::emit(std::any data) {
|
||||||
for (auto& l : listeners) {
|
for (auto& l : listeners) {
|
||||||
// if there is only one lock, it means the event is only held by the listeners
|
// if there is only one lock, it means the event is only held by the listeners
|
||||||
// vector and was removed during our iteration
|
// vector and was removed during our iteration
|
||||||
if (l.strongRef() == 1) {
|
if (l.strongRef() == 1)
|
||||||
dirty = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
l->emit(data);
|
l->emit(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,13 +38,17 @@ void Hyprutils::Signal::CSignal::emit(std::any data) {
|
||||||
// release SPs
|
// release SPs
|
||||||
listeners.clear();
|
listeners.clear();
|
||||||
|
|
||||||
if (dirty)
|
// we cannot release any expired refs here as one of the listeners could've removed this object and
|
||||||
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); });
|
// as such we'd be doing a UAF
|
||||||
}
|
}
|
||||||
|
|
||||||
CHyprSignalListener Hyprutils::Signal::CSignal::registerListener(std::function<void(std::any)> handler) {
|
CHyprSignalListener Hyprutils::Signal::CSignal::registerListener(std::function<void(std::any)> handler) {
|
||||||
CHyprSignalListener listener = makeShared<CSignalListener>(handler);
|
CHyprSignalListener listener = makeShared<CSignalListener>(handler);
|
||||||
m_vListeners.emplace_back(listener);
|
m_vListeners.emplace_back(listener);
|
||||||
|
|
||||||
|
// housekeeping: remove any stale listeners
|
||||||
|
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); });
|
||||||
|
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue