mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-09-25 16:40:33 -04:00
config/actions: fix null derefs in pin dispatcher (#14914)
* hyprtester: add issue14134 regression test D#14134 reports a pin dispatcher SEGV when a monitor hosting a pinned floating window is disabled (e.g. lid close on a laptop). After CMonitor::onDisconnect resets m_activeWorkspace to null, the CMonitor SP stays alive in m_realMonitors, and the pinned- window branch of moveWorkspaceToMonitor leaves the window's m_monitor pointing at the disabled monitor. The next pin dispatch does null deref inside Config::Actions::pinWindow. * config/actions: fix null derefs in pin dispatcher PR #14061 replaced moveToWorkspace(m_activeWorkspace) with assignToSpace(m_activeWorkspace->m_space) and a separate layoutTarget() call. The two new derefs aren't covered by the existing PMONITOR check, and either one being null crashes the compositor. In practice, i use pyprland which uses pining function, and since i am on laptop, sometimes my lid is closed and i have monitor disabled, this causes null deref when computer goes idle. Layout::CWindowTarget::assignToSpace <- segv Config::Actions::pinWindow pin CDispatcherTranslator::run CHyprCtl::getReply In this fix i've added null checks to avoid crashing
This commit is contained in:
@@ -588,6 +588,27 @@ TEST_CASE(issue14038) {
|
||||
// this should not crash hyprland. If we are alive, we good.
|
||||
}
|
||||
|
||||
TEST_CASE(issue14134) {
|
||||
OK(getFromSocket("/output create headless HEADLESS-4"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-4' })"));
|
||||
|
||||
if (!spawnKitty("kitty_14134"))
|
||||
FAIL_TEST("Could not spawn kitty");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'toggle', window = 'class:kitty_14134' })"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.pin({ action = 'toggle', window = 'class:kitty_14134' })"));
|
||||
|
||||
OK(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-4', disabled = true })"));
|
||||
|
||||
// will return error, should not be OK.
|
||||
getFromSocket("/dispatch hl.dsp.window.pin({ action = 'toggle', window = 'class:kitty_14134' })");
|
||||
|
||||
OK(getFromSocket("/reload"));
|
||||
Tests::killAllWindows();
|
||||
ASSERT(Tests::windowCount(), 0);
|
||||
OK(getFromSocket("/output remove HEADLESS-4"));
|
||||
}
|
||||
|
||||
TEST_CASE(specialFloatRecenters) {
|
||||
if (!spawnKitty("kitty_special_float_recenter"))
|
||||
FAIL_TEST("Could not spawn kitty");
|
||||
|
||||
@@ -230,15 +230,22 @@ ActionResult Actions::pinWindow(eTogglableAction action, std::optional<PHLWINDOW
|
||||
if (wantPin == window->m_pinned)
|
||||
return {};
|
||||
|
||||
window->m_pinned = wantPin;
|
||||
window->updateFullscreenInputState();
|
||||
*window->alpha(Desktop::View::WINDOW_ALPHA_FULLSCREEN) = window->isBlockedByFullscreen() ? 0.F : 1.F;
|
||||
|
||||
const auto PMONITOR = window->m_monitor.lock();
|
||||
if (!PMONITOR)
|
||||
return actionError("Window has no monitor", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE);
|
||||
|
||||
window->layoutTarget()->assignToSpace(PMONITOR->m_activeWorkspace->m_space);
|
||||
if (!PMONITOR->m_activeWorkspace || !PMONITOR->m_activeWorkspace->m_space)
|
||||
return actionError("Monitor has no active workspace", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE);
|
||||
|
||||
const auto LAYOUTTARGET = window->layoutTarget();
|
||||
if (!LAYOUTTARGET)
|
||||
return actionError("Window has no layout target", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE);
|
||||
|
||||
window->m_pinned = wantPin;
|
||||
window->updateFullscreenInputState();
|
||||
*window->alpha(Desktop::View::WINDOW_ALPHA_FULLSCREEN) = window->isBlockedByFullscreen() ? 0.F : 1.F;
|
||||
|
||||
LAYOUTTARGET->assignToSpace(PMONITOR->m_activeWorkspace->m_space);
|
||||
window->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_PINNED);
|
||||
|
||||
const auto PWORKSPACE = window->m_workspace;
|
||||
|
||||
Reference in New Issue
Block a user