Bug 514229 - kwin_wayland crashed in KWin::LogicalOutput::scale() when waking up a laptop connected to an external screen
Summary: kwin_wayland crashed in KWin::LogicalOutput::scale() when waking up a laptop ...
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: generic-crash (other bugs)
Version First Reported In: 6.5.80
Platform: Other Linux
: HI crash
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords:
: 514638 (view as bug list)
Depends on:
Blocks:
 
Reported: 2026-01-06 15:26 UTC by Nate Graham
Modified: 2026-01-15 13:38 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed/Implemented In: 6.6.0
Sentry Crash Report:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nate Graham 2026-01-06 15:26:57 UTC
STEPS TO REPRODUCE
1. Have KWin build from git master (2ce9929c4faab90860e069f57f8aed3a967e57a0) on KDE Linux
2. Put laptop to sleep by closing its lid
3. While in that state, plug in a USB-C monitor
4. Open the lid to wake it up


OBSERVED RESULT
kwin_wayland crashed:

#0  0x00007fa4b9ca690c in ??? () at /usr/lib/libc.so.6
#1  0x00007fa4b9c4c3a0 in raise () at /usr/lib/libc.so.6
#2  0x00007fa4bcf736c5 in KCrash::defaultCrashHandler (sig=11)
    at /home/nate/kde/src/kcrash/src/kcrash.cpp:605
#3  0x00007fa4b9c4c4d0 in <signal handler called> () at /usr/lib/libc.so.6
#4  KWin::LogicalOutput::scale (this=this@entry=0x0)
    at /home/nate/kde/src/kwin/src/core/output.cpp:392
#5  0x00007fa4bd2ab2c4 in KWin::LogicalOutput::geometryF (this=this@entry=0x0)
    at /home/nate/kde/src/kwin/src/core/output.cpp:402
#6  0x00007fa4bd284a73 in KWin::Compositor::assignOutputLayers
    (this=0x56357f2b3a50, output=0x56357f134800)
    at /home/nate/kde/src/kwin/src/compositor.cpp:1015
#7  0x00007fa4ba3c834f in ??? () at /usr/lib/libQt6Core.so.6
#8  0x00007fa4bd5e9108 in KWin::DrmOutput::applyQueuedChanges
    (this=this@entry=0x56357f134800, props=std::shared_ptr<KWin::OutputChangeSet> (use count 2, weak count 0) = {...}) at /home/nate/kde/src/kwin/src/backends/drm/drm_output.cpp:492
#9  0x00007fa4bd5ab744 in KWin::DrmBackend::applyOutputChanges (this=0x56357eed0180, config=...)
    at /home/nate/kde/src/kwin/src/backends/drm/drm_backend.cpp:417
#10 0x00007fa4bd54bb18 in KWin::Workspace::applyOutputConfiguration
    (this=0x56357f330db0, config=...) at /home/nate/kde/src/kwin/src/workspace.cpp:526
#11 0x00007fa4bd54bf6e in operator() (__closure=0x56357fbfe4d0)
    at /home/nate/kde/src/kwin/src/workspace.cpp:239
#12 operator() (__closure=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:116
#13 QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<std::integer_sequence<long unsigned int>, QtPrivate::List<>, void, KWin::Workspace::init()::<lambda()> >::call(KWin::Workspace::init()::<lambda()>&, void**)::<lambda()> > (args=<optimized out>, fn=<optimized out>)
    at /usr/include/qt6/QtCore/qobjectdefs_impl.h:65
#14 QtPrivate::FunctorCall<std::integer_sequence<long unsigned int>, QtPrivate::List<>, void, KWin::Workspace::init()::<lambda()> >::call (f=..., arg=<optimized out>)
    at /usr/include/qt6/QtCore/qobjectdefs_impl.h:115
#15 QtPrivate::FunctorCallable<KWin::Workspace::init()::<lambda()> >::call<QtPrivate::List<>, void> (f=..., arg=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:337
#16 QtPrivate::QCallableObject<KWin::Workspace::init()::<lambda()>, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *)
    (which=<optimized out>, this_=0x56357fbfe4c0, r=<optimized out>, a=<optimized out>, ret=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:547
#17 0x00007fa4ba3c834f in ??? () at /usr/lib/libQt6Core.so.6
#18 0x00007fa4bd36294d in KWin::InputRedirection::processSpies<void (KWin::InputEventSpy::*)(KWin::SwitchEvent*), KWin::SwitchEvent*> (this=<optimized out>, method=<optimized out>)
    at /home/nate/kde/src/kwin/src/input.h:166
#19 operator()
    (__closure=<optimized out>, state=<optimized out>, time=std::chrono::duration = { <optimized out>us }, device=<optimized out>) at /home/nate/kde/src/kwin/src/input.cpp:3329
#20 operator() (__closure=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:116
#21 QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<std::integer_sequence<long unsigned int, 0, 1, 2>, QtPrivate::List<KWin::SwitchState, std::chrono::duration<long int, std::ratio<1, 1000000> >, KWin::InputDevice*>, void, KWin::InputRedirection::addInputDevice(KWin::InputDevice*)::<lambda(KWin::SwitchState, std::chrono::microseconds, KWin::InputDevice*)> >::call(KWin::InputRedirection::addInputDevice(KWin::InputDevice*)::<lambda(KWin::SwitchState, std::chrono::microseconds, KWin::InputDevice*)>&, void**)::<lambda()> > (args=<optimized out>, fn=<optimized out>)
    at /usr/include/qt6/QtCore/qobjectdefs_impl.h:65
#22 QtPrivate::FunctorCall<std::integer_sequence<long unsigned int, 0, 1, 2>, QtPrivate::List<KWin::SwitchState, std::chrono::duration<long int, std::ratio<1, 1000000> >, KWin::InputDevice*>, void, KWin::InputRedirection::addInputDevice(KWin::InputDevice*)::<lambda(KWin::SwitchState, std::chrono::microseconds, KWin::InputDevice*)> >::call (f=<optimized out>, arg=<optimized out>)
    at /usr/include/qt6/QtCore/qobjectdefs_impl.h:115
#23 QtPrivate::FunctorCallable<KWin::InputRedirection::addInputDevice(KWin::InputDevice*)::<lambda(KWin::SwitchState, std::chrono::microseconds, KWin::InputDevice*)>, KWin::SwitchState, std::chrono::duration<long int, std::ratio<1, 1000000> >, KWin::InputDevice*>::call<QtPrivate::List<KWin::SwitchState, std::chrono::duration<long, std::ratio<1, 1000000> >, KWin::InputDevice*>, void>
    (f=<optimized out>, arg=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:337
#24 QtPrivate::QCallableObject<KWin::InputRedirection::addInputDevice(KWin::InputDevice*)::<lambda(KWin::SwitchState, std::chrono::microseconds, KWin::InputDevice*)>, QtPrivate::List<KWin::SwitchState, std::chrono::duration<long int, std::ratio<1, 1000000> >, KWin::InputDevice*>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *)
    (which=<optimized out>, this_=<optimized out>, r=<optimized out>, a=<optimized out>, ret=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:547
#25 0x00007fa4ba3c8418 in ??? () at /usr/lib/libQt6Core.so.6
#26 0x00007fa4bd2a7d7d in QMetaObject::activate<void, KWin::SwitchState, std::chrono::duration<long, std::ratio<1l, 1000000l> >, KWin::InputDevice*>
    (sender=0x56357fe81ec0, mo=0x7fa4bd906620 <KWin::InputDevice::staticMetaObject>, local_signal_index=22, ret=0x0) at /usr/include/qt6/QtCore/qobjectdefs.h:319
#27 KWin::InputDevice::switchToggle
    (this=this@entry=0x56357fe81ec0, _t1=<optimized out>, _t2=_t2@entry=std::chrono::duration = { 203253572383us }, _t3=<optimized out>, _t3@entry=0x56357fe81ec0)
    at /home/nate/kde/build/kwin/src/kwin_autogen/include/moc_inputdevice.cpp:851
#28 0x00007fa4bd60b6fc in KWin::LibInput::Connection::processEvents (this=0x56357f1d5260)
    at /home/nate/kde/src/kwin/src/backends/libinput/connection.cpp:474
#29 0x00007fa4ba3b5994 in QObject::event(QEvent*) () at /usr/lib/libQt6Core.so.6
#30 0x00007fa4bb52b1c0 in QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
    at /usr/lib/libQt6Widgets.so.6
#31 0x00007fa4ba35b958 in QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
    at /usr/lib/libQt6Core.so.6
#32 0x00007fa4ba35bd30 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*)
    () at /usr/lib/libQt6Core.so.6
#33 0x00007fa4ba51ed4d in QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt6Core.so.6
#34 0x00007fa4bb200b73 in QUnixEventDispatcherQPA::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt6Gui.so.6
#35 0x00007fa4ba366786 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()
    at /usr/lib/libQt6Core.so.6
#36 0x00007fa4ba3603f1 in QCoreApplication::exec() () at /usr/lib/libQt6Core.so.6
#37 0x000056355f4f2e94 in main (argc=<optimized out>, argv=<optimized out>)
    at /home/nate/kde/src/kwin/src/main_wayland.cpp:634
(gdb) 


SOFTWARE/OS VERSIONS
Operating System: KDE Linux 2025-12-31
KDE Plasma Version: 6.5.80
KDE Frameworks Version: 6.23.0
Qt Version: 6.10.1
Kernel Version: 6.18.2-zen2-1-zen (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 7840U w/ Radeon™ 780M Graphics
Memory: 17 GB of RAM (16.0 GB usable)
Graphics Processor: AMD Radeon 780M Graphics
Comment 1 TraceyC 2026-01-07 18:10:46 UTC
I'm not able to reproduce this on kwin & Plasma built from today's git master
Comment 2 Zamundaaa 2026-01-07 19:39:27 UTC
Doing that doesn't cause a crash here either
Comment 3 Nate Graham 2026-01-08 17:50:42 UTC
Hmm, it isn't happening anymore here either. Maybe it got fixed by something.

Will re-open if I notice it happening again.
Comment 4 Vlad Zahorodnii 2026-01-12 12:13:38 UTC
#5  0x00007fa4bd2ab2c4 in KWin::LogicalOutput::geometryF (this=this@entry=0x0)
    at /home/nate/kde/src/kwin/src/core/output.cpp:402
#6  0x00007fa4bd284a73 in KWin::Compositor::assignOutputLayers
    (this=0x56357f2b3a50, output=0x56357f134800)
    at /home/nate/kde/src/kwin/src/compositor.cpp:1015
#7  0x00007fa4ba3c834f in ??? () at /usr/lib/libQt6Core.so.6
#8  0x00007fa4bd5e9108 in KWin::DrmOutput::applyQueuedChanges
    (this=this@entry=0x56357f134800, props=std::shared_ptr<KWin::OutputChangeSet> (use count 2, weak count 0) = {...}) at /home/nate/kde/src/kwin/src/backends/drm/drm_output.cpp:492
#9  0x00007fa4bd5ab744 in KWin::DrmBackend::applyOutputChanges (this=0x56357eed0180, config=...)
    at /home/nate/kde/src/kwin/src/backends/drm/drm_backend.cpp:417
#10 0x00007fa4bd54bb18 in KWin::Workspace::applyOutputConfiguration
    (this=0x56357f330db0, config=...) at /home/nate/kde/src/kwin/src/workspace.cpp:526

The Compositor getting triggered by applyOutputConfiguration() seems super duper wrong. The logical outputs are created later after applying the output configuration. Even if the crash doesn't happen now, we have some architectural issues.
Comment 5 Vlad Zahorodnii 2026-01-12 12:21:48 UTC
After having a second look at code, I see some issues with the outputLayersChanged signal management.
Comment 6 Bug Janitor Service 2026-01-13 20:55:21 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/8642
Comment 7 Zamundaaa 2026-01-14 14:47:14 UTC
Git commit c1ce6ef3f040c047cd29e482237404672ba108f5 by Xaver Hugl.
Committed on 14/01/2026 at 14:18.
Pushed by zamundaaa into branch 'master'.

compositor: only update output layers in response to Workspace::outputsChanged

Processing output changes before workspace gets a chance to create and update
logical outputs can cause problems, for example if
- you disable an output -> logical output gets removed
- some unrelated output changes happen
- you enable the output again, and different output layers get assigned than
  before

In that case, Compositor::assignOutputLayers would get called while there's no
logical output yet, and thus KWin crashes.

Outputs layers can only change in situations where workspace will later emit
outputsChanged, so the intermediary actions were unnecessary either way.

M  +0    -4    src/backends/drm/drm_pipeline.cpp
M  +0    -1    src/backends/drm/drm_virtual_output.cpp
M  +0    -4    src/compositor.cpp
M  +0    -2    src/core/backendoutput.h

https://invent.kde.org/plasma/kwin/-/commit/c1ce6ef3f040c047cd29e482237404672ba108f5
Comment 8 Vlad Zahorodnii 2026-01-14 16:12:53 UTC
Git commit 31d3aec7e48a8c7e110678c10f0d936de5b3dd86 by Vlad Zahorodnii, on behalf of Xaver Hugl.
Committed on 14/01/2026 at 15:29.
Pushed by zamundaaa into branch 'Plasma/6.6'.

compositor: only update output layers in response to Workspace::outputsChanged

Processing output changes before workspace gets a chance to create and update
logical outputs can cause problems, for example if
- you disable an output -> logical output gets removed
- some unrelated output changes happen
- you enable the output again, and different output layers get assigned than
  before

In that case, Compositor::assignOutputLayers would get called while there's no
logical output yet, and thus KWin crashes.

Outputs layers can only change in situations where workspace will later emit
outputsChanged, so the intermediary actions were unnecessary either way.
(cherry picked from commit c1ce6ef3f040c047cd29e482237404672ba108f5)

M  +0    -4    src/backends/drm/drm_pipeline.cpp
M  +0    -1    src/backends/drm/drm_virtual_output.cpp
M  +0    -4    src/compositor.cpp
M  +0    -2    src/core/backendoutput.h

https://invent.kde.org/plasma/kwin/-/commit/31d3aec7e48a8c7e110678c10f0d936de5b3dd86
Comment 9 Vlad Zahorodnii 2026-01-15 13:38:43 UTC
*** Bug 514638 has been marked as a duplicate of this bug. ***