framescheduler: fix edge case crashes

rare UAFs because renderMonitor can call onDisconnect (ugh, that should be changed...)

fixes #11073
This commit is contained in:
vaxerski 2025-08-16 16:52:28 +02:00
parent 1cbb62ed6a
commit 78c9e2080c
3 changed files with 38 additions and 12 deletions

View file

@ -63,7 +63,10 @@ void CMonitor::onConnect(bool noRule) {
g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); }); g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); });
m_listeners.frame = m_output->events.frame.listen([this] { m_frameScheduler->onFrame(); }); m_listeners.frame = m_output->events.frame.listen([this] {
if (m_frameScheduler)
m_frameScheduler->onFrame();
});
m_listeners.commit = m_output->events.commit.listen([this] { m_listeners.commit = m_output->events.commit.listen([this] {
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(m_self.lock()); PROTO::screencopy->onOutputCommit(m_self.lock());
@ -127,7 +130,8 @@ void CMonitor::onConnect(bool noRule) {
applyMonitorRule(&rule); applyMonitorRule(&rule);
}); });
m_frameScheduler = makeUnique<CMonitorFrameScheduler>(m_self.lock()); m_frameScheduler = makeUnique<CMonitorFrameScheduler>(m_self.lock());
m_frameScheduler->m_self = WP<CMonitorFrameScheduler>(m_frameScheduler);
m_tearingState.canTear = m_output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; m_tearingState.canTear = m_output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;

View file

@ -36,7 +36,16 @@ void CMonitorFrameScheduler::onSyncFired() {
m_renderAtFrame = false; // block frame rendering, we already scheduled m_renderAtFrame = false; // block frame rendering, we already scheduled
m_lastRenderBegun = hrc::now(); m_lastRenderBegun = hrc::now();
// get a ref to ourselves. renderMonitor can destroy this scheduler if it decides to perform a monitor reload
// FIXME: this is horrible. "renderMonitor" should not be able to do that.
auto self = m_self;
g_pHyprRenderer->renderMonitor(m_monitor.lock(), false); g_pHyprRenderer->renderMonitor(m_monitor.lock(), false);
if (!self)
return;
onFinishRender(); onFinishRender();
} }
@ -99,14 +108,23 @@ void CMonitorFrameScheduler::onFrame() {
Debug::log(TRACE, "CMonitorFrameScheduler: {} -> frame event, render = true, rendering normally.", m_monitor->m_name); Debug::log(TRACE, "CMonitorFrameScheduler: {} -> frame event, render = true, rendering normally.", m_monitor->m_name);
m_lastRenderBegun = hrc::now(); m_lastRenderBegun = hrc::now();
// get a ref to ourselves. renderMonitor can destroy this scheduler if it decides to perform a monitor reload
// FIXME: this is horrible. "renderMonitor" should not be able to do that.
auto self = m_self;
g_pHyprRenderer->renderMonitor(m_monitor.lock()); g_pHyprRenderer->renderMonitor(m_monitor.lock());
if (!self)
return;
onFinishRender(); onFinishRender();
} }
void CMonitorFrameScheduler::onFinishRender() { void CMonitorFrameScheduler::onFinishRender() {
m_sync = CEGLSync::create(); // this destroys the old sync m_sync = CEGLSync::create(); // this destroys the old sync
g_pEventLoopManager->doOnReadable(m_sync->fd().duplicate(), [this, mon = m_monitor] { g_pEventLoopManager->doOnReadable(m_sync->fd().duplicate(), [this, self = m_self] {
if (!mon) // might've gotten destroyed if (!self) // might've gotten destroyed
return; return;
onSyncFired(); onSyncFired();
}); });

View file

@ -22,15 +22,19 @@ class CMonitorFrameScheduler {
void onFrame(); void onFrame();
private: private:
bool canRender(); bool canRender();
void onFinishRender(); void onFinishRender();
bool newSchedulingEnabled(); bool newSchedulingEnabled();
bool m_renderAtFrame = true; bool m_renderAtFrame = true;
bool m_pendingThird = false; bool m_pendingThird = false;
hrc::time_point m_lastRenderBegun; hrc::time_point m_lastRenderBegun;
PHLMONITORREF m_monitor; PHLMONITORREF m_monitor;
UP<CEGLSync> m_sync; UP<CEGLSync> m_sync;
WP<CMonitorFrameScheduler> m_self;
friend class CMonitor;
}; };