Bug 501828 - Crash with non-sense Gtk4 code
Summary: Crash with non-sense Gtk4 code
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: wayland-generic (show other bugs)
Version: 6.3.3
Platform: Other Linux
: NOR crash
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-03-21 13:35 UTC by postix
Modified: 2025-03-25 14:40 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In: 6.3.4
Sentry Crash Report: https://crash-reports.kde.org/organizations/kde/issues/99993/events/e1773db6bc584c388c32a307713ca38c?project=12


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description postix 2025-03-21 13:35:35 UTC
SUMMARY

I've stumbled over the following two issues by accident:

1) If a Gtk4 popovermenu is set visible in the _closed_ event, it will re-open and steal the focus: You can no longer click anything else, but need to kill the app in another tty

2) If you additionally make the popover invisible afterwards, it will crash kwin. Could reproduce it on Fedora 41 with Gtk 4.16.12 and openSUSE Tumbleweed with Gtk 4.18.2, both running Kwin 6.3.3 Wayland.
If it doesn't crash immediately for you, keep clicking to close the popover, eventually it should.

The code of course makes no sense, but I wanted to report it nonetheless. 


STEPS TO REPRODUCE

Here's a minimal  reproducer:

```
import gi
gi.require_version("Gtk", "4.0")

from gi.repository import Gtk
from gi.repository import GLib

def hide_popover(popover):
    popover.set_visible(False)

def on_closed(popover):
    print("popover closed")
    popover.set_visible(True)

    # The following line makes kwin eventually crash
    # Commment it out instead for permanent focus stealing
    GLib.timeout_add(100, hide_popover, popover)

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app)

    popovermenu = Gtk.PopoverMenu()
    popovermenu.connect("closed", on_closed)
    popovermenu.set_size_request(100, 100)

    win.set_child(popovermenu)

    popovermenu.popup()
    win.present()


app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)
```

SOFTWARE/OS VERSIONS
Operating System: openSUSE Tumbleweed 20250318
KDE Plasma Version: 6.3.3
KDE Frameworks Version: 6.12.0
Qt Version: 6.8.2
Kernel Version: 6.13.6-1-default (64-bit)
Comment 1 postix 2025-03-21 13:39:59 UTC
If you click fast and often enough onto the "x" button in the titlebar of the sample app, you can make it close in the case of permanent focus stealing.
Comment 2 postix 2025-03-21 13:43:38 UTC
You can also click into into another app, e.g. Konsole, until eventually Konsole will gain focus. The main window will hide behind Konsole, but the popover keeps staying on top of all windows.
Comment 3 postix 2025-03-21 13:47:37 UTC
Backtrace of the crash:

```
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=11, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007f3e1dc9b453 in __pthread_kill_internal (threadid=<optimized out>, signo=11) at pthread_kill.c:89
#2  0x00007f3e1dc41cb6 in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26
#3  0x00007f3e21aa4a37 in KCrash::defaultCrashHandler (sig=11) at /usr/src/debug/kcrash-6.12.0/src/kcrash.cpp:605
#4  0x00007f3e1dc41e00 in <signal handler called> () at /lib64/libc.so.6
#5  0x00007f3e21692129 in KWin::XdgPopupWindow::transientPlacement (this=0x5558c07d4790)
    at /usr/src/debug/kwin-6.3.3/src/xdgshellwindow.cpp:1787
#6  0x00007f3e2158d313 in KWin::Placement::placeTransient (this=<optimized out>, c=0x5558c07d4790)
    at /usr/src/debug/kwin-6.3.3/src/placement.cpp:512
#7  0x00007f3e21665d21 in KWin::Workspace::addWaylandWindow (this=0x5558bef5c0d0, window=0x5558c07d4790)
    at /usr/include/c++/14/bits/unique_ptr.h:193
#8  0x00007f3e1e60ed61 in QtPrivate::QSlotObjectBase::call
    (this=0x5558bf0e2250, r=<optimized out>, a=0x7ffe3ac13590, this=<optimized out>, r=<optimized out>, a=<optimized out>)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobjectdefs_impl.h:486
#9  doActivate<false> (sender=0x5558be0ce270, signal_index=3, argv=0x7ffe3ac13590)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobject.cpp:4115
#10 0x00007f3e2163802f in KWin::WaylandServer::windowAdded (this=<optimized out>, _t1=<optimized out>)
    at /usr/src/debug/kwin-6.3.3/build/src/kwin_autogen/include/moc_wayland_server.cpp:199
#11 0x00007f3e1e60ed61 in QtPrivate::QSlotObjectBase::call
    (this=0x5558c0d66f00, r=<optimized out>, a=0x7ffe3ac13658, this=<optimized out>, r=<optimized out>, a=<optimized out>)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobjectdefs_impl.h:486
#12 doActivate<false> (sender=0x5558c07d4790, signal_index=61, argv=0x7ffe3ac13658)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobject.cpp:4115
#13 0x00007f3e1e60ed61 in QtPrivate::QSlotObjectBase::call
    (this=0x5558c03d8740, r=<optimized out>, a=0x7ffe3ac13748, this=<optimized out>, r=<optimized out>, a=<optimized out>)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobjectdefs_impl.h:486
#14 doActivate<false> (sender=0x5558bf004ff0, signal_index=26, argv=0x7ffe3ac13748)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobject.cpp:4115
#15 0x00007f3e217c8dc8 in KWin::SurfaceInterfacePrivate::applyState (this=0x5558bf508330, next=<optimized out>)
    at /usr/src/debug/kwin-6.3.3/src/wayland/surface.cpp:737
#16 0x00007f3e217f7d56 in KWin::Transaction::apply (this=0x5558bf6539c0)
    at /usr/src/debug/kwin-6.3.3/src/wayland/transaction.cpp:229
#17 0x00007f3e217f7eac in KWin::Transaction::tryApply (this=0x5558bf6539c0)
    at /usr/src/debug/kwin-6.3.3/src/wayland/transaction.cpp:262
#18 0x00007f3e217f545c in operator() (__closure=0x5558c0d5e6d0) at /usr/src/debug/kwin-6.3.3/src/wayland/transaction.cpp:51
#19 operator() (__closure=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:141
#20 QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, KWin::TransactionDmaBufLocker::TransactionDmaBufLocker(const KWin::DmaBufAttributes*)::<lambda()> >::call(KWin::TransactionDmaBufLocker::TransactionDmaBufLocker(const KWin::DmaBufAttributes*)::<lambda()>&, void**)::<lambda()> >
    (args=<optimized out>, fn=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:65
#21 QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, KWin::TransactionDmaBufLocker::TransactionDmaBufLocker(const KWin::DmaBufAttributes*)::<lambda()> >::call (f=..., arg=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:140
#22 QtPrivate::FunctorCallable<KWin::TransactionDmaBufLocker::TransactionDmaBufLocker(const KWin::DmaBufAttributes*)::<lambda()> >::call<QtPrivate::List<>, void> (f=..., arg=<optimized out>) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:362
#23 QtPrivate::QCallableObject<KWin::TransactionDmaBufLocker::TransactionDmaBufLocker(const KWin::DmaBufAttributes*)::<lambda()>, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *)
    (which=<optimized out>, this_=0x5558c0d5e6c0, r=<optimized out>, a=<optimized out>, ret=<optimized out>)
    at /usr/include/qt6/QtCore/qobjectdefs_impl.h:572
#24 0x00007f3e1e60ed61 in QtPrivate::QSlotObjectBase::call
    (this=0x5558c0d5e6c0, r=<optimized out>, a=0x7ffe3ac13bc0, this=<optimized out>, r=<optimized out>, a=<optimized out>)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobjectdefs_impl.h:486
#25 doActivate<false> (sender=0x5558bf591d30, signal_index=3, argv=0x7ffe3ac13bc0)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qobject.cpp:4115
#26 0x00007f3e1e611ec3 in QSocketNotifier::activated (this=this@entry=0x5558bf591d30, _t1=..., _t2=<optimized out>, _t3=...)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/build/src/corelib/Core_autogen/include/moc_qsocketnotifier.cpp:198
#27 0x00007f3e1e612aae in QSocketNotifier::event (this=0x5558bf591d30, e=<optimized out>)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qsocketnotifier.cpp:327
#28 0x00007f3e1f9dee35 in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x5558bf591d30, e=0x7ffe3ac13d00)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/widgets/kernel/qapplication.cpp:3296
#29 0x00007f3e1e5adaf0 in QCoreApplication::notifyInternal2 (receiver=0x5558bf591d30, event=0x7ffe3ac13d00)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qcoreapplication.cpp:1172
#30 0x00007f3e1e71f9a4 in QEventDispatcherUNIXPrivate::activateSocketNotifiers (this=0x5558be03e9e0)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qeventdispatcher_unix.cpp:254
#31 0x00007f3e1e72529a in QEventDispatcherUNIX::processEvents (this=<optimized out>, flags=..., flags@entry=...)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/kernel/qeventdispatcher_unix.cpp:470
#32 0x00007f3e1f2adf91 in QUnixEventDispatcherQPA::processEvents (this=<optimized out>, flags=...)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/gui/platform/unix/qunixeventdispatcher.cpp:27
#33 0x00007f3e1e5b599b in QEventLoop::exec (this=this@entry=0x7ffe3ac13ed0, flags=..., flags@entry=...)
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/global/qflags.h:34
#34 0x00007f3e1e5b765a in QCoreApplication::exec () at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/corelib/global/qflags.h:74
#35 0x00007f3e1ee0f700 in QGuiApplication::exec ()
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/gui/kernel/qguiapplication.cpp:1975
#36 0x00007f3e1f9dc0f9 in QApplication::exec ()
    at /usr/src/debug/qtbase-everywhere-src-6.8.2/src/widgets/kernel/qapplication.cpp:2564
#37 0x00005558b053de52 in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/kwin-6.3.3/src/main_wayland.cpp:622
```
Comment 4 postix 2025-03-21 13:54:54 UTC
I've split the two issues and created another one for the focus stealing: #501829. So this one here is only about Kwin crashing now.
Comment 5 Bug Janitor Service 2025-03-24 07:48:41 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/7386
Comment 6 Vlad Zahorodnii 2025-03-24 16:28:51 UTC
Git commit 93c9103ed3e1374d34394225ee3aa6cf8c8c955a by Vlad Zahorodnii.
Committed on 24/03/2025 at 16:08.
Pushed by vladz into branch 'master'.

wayland: Guard against unconfigured buffers

The xdg shell protocol says that a protocol error will be raised if a
client attempts to attach a wl_buffer before a configure event is sent.

M  +36   -0    autotests/integration/xdgshellwindow_test.cpp
M  +20   -6    src/wayland/xdgshell.cpp
M  +4    -0    src/xdgshellwindow.cpp

https://invent.kde.org/plasma/kwin/-/commit/93c9103ed3e1374d34394225ee3aa6cf8c8c955a
Comment 7 Bug Janitor Service 2025-03-24 16:41:42 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/7393
Comment 8 Vlad Zahorodnii 2025-03-25 06:15:26 UTC
Git commit 76ab7f20c2593f7d91f9ce308ebb99896ac4027d by Vlad Zahorodnii.
Committed on 25/03/2025 at 05:56.
Pushed by vladz into branch 'Plasma/6.3'.

wayland: Guard against unconfigured buffers

The xdg shell protocol says that a protocol error will be raised if a
client attempts to attach a wl_buffer before a configure event is sent.


(cherry picked from commit 93c9103ed3e1374d34394225ee3aa6cf8c8c955a)

Co-authored-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>

M  +36   -0    autotests/integration/xdgshellwindow_test.cpp
M  +20   -6    src/wayland/xdgshell.cpp
M  +4    -0    src/xdgshellwindow.cpp

https://invent.kde.org/plasma/kwin/-/commit/76ab7f20c2593f7d91f9ce308ebb99896ac4027d
Comment 9 TraceyC 2025-03-25 14:40:28 UTC
A merge request has been merged which should fix this in Plasma 6.3.4. If you still see this crash in that version, please reopen this report. Thanks!