Bug 515465 - xdg-desktop-portal-kde crashes with SIGSEGV when clipboard data requested by Klipper (Qt threading violation)
Summary: xdg-desktop-portal-kde crashes with SIGSEGV when clipboard data requested by ...
Status: ASSIGNED
Alias: None
Product: xdg-desktop-portal-kde
Classification: Plasma
Component: general (other bugs)
Version First Reported In: 6.5.5
Platform: openSUSE Linux
: HI normal
Target Milestone: ---
Assignee: Plasma Bugs List
URL:
Keywords: regression
: 515433 (view as bug list)
Depends on:
Blocks:
 
Reported: 2026-02-03 16:29 UTC by Greg Lamberson
Modified: 2026-02-04 14:42 UTC (History)
7 users (show)

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


Attachments
Git patch: Fix clipboard threading bug using QMetaObject::invokeMethod() (2.72 KB, patch)
2026-02-03 16:39 UTC, Greg Lamberson
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Greg Lamberson 2026-02-03 16:29:53 UTC
SUMMARY
xdg-desktop-portal-kde crashes with SIGSEGV when clipboard data requested by Klipper (Qt threading violation)

STEPS TO REPRODUCE
Use KDE Plasma with Klipper enabled (default configuration, integrated into plasmashell)
Connect a remote desktop client that uses Portal Clipboard (e.g., RDP server using xdg-desktop-portal API)
Call org.freedesktop.impl.portal.Clipboard.SetSelection via D-Bus with MIME types
Wait 2-3 seconds for Klipper to monitor and read the clipboard
Observe crash
OBSERVED RESULT
Portal crashes with SIGSEGV in QMimeData::data(). The crash occurs on KSystemClipboard’s Wayland thread approximately 2 seconds after SetSelection is called. All clipboard functionality stops working. The crash is 100% reproducible.

EXPECTED RESULT
Portal continues running, clipboard data is transferred successfully to the requesting application (Klipper), and clipboard remains functional.

SOFTWARE/OS VERSIONS
Operating System: openSUSE Tumbleweed 20260131 KDE Plasma Version: 6.5.5 KDE Frameworks Version: 6.22.0 Qt Version: 6.10.1 Kernel Version: 6.18.7-1-default (64-bit) Graphics Platform: offscreen xdg-desktop-portal-kde: 6.5.5-1.1

BACKTRACE
Stack trace of thread 2450 (Wayland thread - where crash occurs):
#0  0x00007f0ba809dd3c __pthread_kill_implementation (libc.so.6 + 0x9dd3c)
#1  0x00007f0ba80427b6 raise (libc.so.6 + 0x427b6)
#2  0x00007f0bab42f360 _ZN6KCrash19defaultCrashHandlerEi (libKF6Crash.so.6 + 0x8360)
#3  0x00007f0ba8042910 __restore_rt (libc.so.6 + 0x42910)
#4  0x00007f0ba8a1ec95 n/a (libQt6Core.so.6 + 0x21ec95)
#5  0x00007f0ba8a1ee7c n/a (libQt6Core.so.6 + 0x21ee7c)
#6  0x00007f0ba8a1fece _ZNK9QMimeData4dataERK7QString (libQt6Core.so.6 + 0x21fece) ← CRASH HERE
#7  0x00007f0bab929f2c n/a (libKF6GuiAddons.so.6 + 0x40f2c) ← DataControlSource::ext_data_control_source_v1_send
#8  0x00007f0bab91f468 n/a (libKF6GuiAddons.so.6 + 0x36468) ← DataControlDevice
#9  0x00007f0bab41ec92 n/a (libffi.so.8 + 0x7c92)
#10 0x00007f0bab41ba26 n/a (libffi.so.8 + 0x4a26)
#11 0x00007f0bab41e2ae ffi_call (libffi.so.8 + 0x72ae)
#12 0x00007f0babbd77f3 n/a (libwayland-client.so.0 + 0x77f3)
#13 0x00007f0babbd8539 n/a (libwayland-client.so.0 + 0x8539)
#14 0x00007f0babbd88eb wl_display_dispatch_queue_pending (libwayland-client.so.0 + 0x88eb)
#15 0x00007f0babbdbdad wl_display_dispatch_queue_timeout (libwayland-client.so.0 + 0xbdad)
#16 0x00007f0babbdbe7b wl_display_dispatch_queue (libwayland-client.so.0 + 0xbe7b)
#17 0x00007f0bab923626 n/a (libKF6GuiAddons.so.6 + 0x3a626) ← ClipboardThread::run
#18 0x00007f0ba8b71e68 n/a (libQt6Core.so.6 + 0x371e68)
#19 0x00007f0ba809bdf1 start_thread (libc.so.6 + 0x9bdf1)
#20 0x00007f0ba8120c8c __clone3 (libc.so.6 + 0x120c8c)
ADDITIONAL INFORMATION
Root Cause Analysis
This is a Qt threading violation in the clipboard portal implementation (src/clipboard.cpp).

The threading violation:

PortalMimeData is created on the main thread (clipboard.cpp:153)
It stores raw pointers to main-thread QObjects:
ClipboardPortal *m_portal (main-thread QObject)
Session *m_session (main-thread QObject)
KSystemClipboard::setMimeData() wraps it in DataControlSource and moves it to the Wayland thread (waylandclipboard.cpp:652: source->moveToThread(m_thread.get()))
When Klipper requests clipboard data, the Wayland thread calls PortalMimeData::retrieveData() (clipboard.cpp:39-46)
This accesses m_portal->fetchData() from the wrong thread, violating Qt’s threading rules
Result: SIGSEGV in QMimeData::data()
Qt documentation states:

“You must not access a QObject from a thread other than the one that created it.”

The clipboard portal violates this fundamental Qt threading rule.

Why Klipper Triggers It
Klipper is integrated into plasmashell (not a separate process) and monitors all clipboard changes via KSystemClipboard::changed signal. When new clipboard content is announced via Portal SetSelection, Klipper reads the data after approximately 1-2 seconds (documented Klipper “takeover” behavior).

This read triggers the Wayland compositor to call back into DataControlSource::ext_data_control_source_v1_send() on the Wayland thread to actually transfer the data. The callback tries to call mimeData->data() on PortalMimeData, which then attempts to access main-thread QObjects from the Wayland thread, causing the crash.

Since Klipper is always active on default KDE Plasma, this bug makes Portal Clipboard completely unusable.

Impact
Severity: Critical - 100% reproducible crash
Affected users: All remote desktop applications using Portal Clipboard on KDE Plasma
Examples: RDP servers, VNC servers, screen sharing tools, clipboard sharing applications
Workaround: None available for end users (requires code fix)
Historical Context
The original clipboard portal implementation (commit 2de83ee0, December 2024) included a prescient comment from the author:

“If this turns out to be problematic in the future, we can either move ClipboardPortal into a separate thread and let it do it’s thing there and block the main thread (for a short time). Or implement the data control protocol directly.”

The author anticipated threading issues but didn’t realize KSystemClipboard already uses a separate Wayland thread (added in kguiaddons commit b71af4e to fix similar threading bugs: BUG 480448, 496029, 502831, 505281, 506467, 507792, 509065, 509689, 511736).

Fix Available
I have developed and tested a fix for this issue. The fix uses QMetaObject::invokeMethod() with Qt::BlockingQueuedConnection to safely marshal cross-thread calls back to the main thread, respecting Qt’s threading requirements while preserving the synchronous API.

The fix changes PortalMimeData::retrieveData() to:

Check if current thread matches portal’s thread
If different, use QMetaObject::invokeMethod() to dispatch to main thread
If same, direct call (fast path)
Change member pointers to QPointer for null-safety
Full technical analysis and patch available in merge request: (will reference MR number here after submission)

Reproducer
The crash can be reproduced with any application using the Portal Clipboard API:

Remote desktop servers (RDP, VNC)
Screen sharing applications
Clipboard synchronization tools
Test application: lamco-rdp-server (https://github.com/gregcman/lamco-rdp-server)

Debug Symbols
Note: Backtrace shown is without debug symbols. For detailed backtrace with symbols, install:

sudo zypper install xdg-desktop-portal-kde6-debuginfo kf6-kguiaddons-debuginfo libQt6Core6-debuginfo
However, the crash location is clear from the stack trace:

Thread 2450 (Wayland thread) calling QMimeData::data()
Called from DataControlSource::ext_data_control_source_v1_send() in libKF6GuiAddons
Which is the Wayland clipboard callback
Source Code Location
File: src/clipboard.cpp Class: PortalMimeData (lines 25-50) Method: retrieveData() (lines 39-46)

QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const override
{
    Q_UNUSED(preferredType);
    if (!m_formats.contains(mimetype)) {
        return QVariant();
    }
    return m_portal->fetchData(m_session, mimetype);  // ← UNSAFE CROSS-THREAD ACCESS
}
This method is called from the Wayland thread but accesses main-thread QObjects.
Comment 1 Greg Lamberson 2026-02-03 16:39:07 UTC
Created attachment 189189 [details]
Git patch: Fix clipboard threading bug using QMetaObject::invokeMethod()

Fix attached as git-formatted patch.

The patch uses QMetaObject::invokeMethod() with Qt::BlockingQueuedConnection to safely marshal cross-thread calls back to the main thread, respecting Qt's threading requirements while preserving the synchronous API.

The fix:
- Detects when retrieveData() is called from a different thread (Wayland thread)
- Uses Qt's thread-safe invokeMethod to call fetchData() on the main thread
- Falls back to direct call when already on the main thread (fast path)
- Changes raw pointers to QPointer for null-safety

Tested on:
- KDE Plasma 6.5.5
- openSUSE Tumbleweed 20260131
- Qt 6.10.1

Results:
- Eliminates 100% reproducible crash
-  Clipboard works bidirectionally
-  No threading warnings
-  Klipper integration works correctly

The patch can be applied with:
  git apply 0001-fix-clipboard-threading-bug-515465.patch

Or reviewed/merged directly into the repository.
Comment 2 Nicolas Fella 2026-02-03 16:40:06 UTC
Please submit patches via https://invent.kde.org
Comment 3 David Edmundson 2026-02-03 16:47:24 UTC
>ext_data_control_source_v1_send

The stack trace has no correlation to everything else in the commentary. 

Someone is copying from the data from the portal, not the portal reading the clipboard 
It's worth noting the mimedata is guarded with a mutex. Clearly something is broken, but not related to what you've written.  Mimedata access is guarded.

If it is AI written, please don't. I would rather have less text than wrong text.

>https://github.com/gregcman/lamco-rdp-server

This doesn't load, is it private?
Comment 4 Greg Lamberson 2026-02-03 16:52:05 UTC
here's the affected versions information according to my quick checking: 

Bug introduced: v6.3.90 (May 15, 2025)                                                                                     
Affected range: v6.3.90 → v6.5.5 (current)                                                                                 
Duration: 9 months, ~19 releases                                                                                           
Fix target: v6.5.6 or v6.6.0
Comment 5 Greg Lamberson 2026-02-03 17:07:18 UTC
Hey David, 

Yes', I'm trying to hurry, but there is correlation. LEt me explain.
The crash occurs in the Wayland thread when Klipper requests clipboard data FROM our clipboard source:

Thread 2450 (Wayland thread): #6 _ZNK9QMimeData4dataERK7QString (libQt6Core.so.6) #7 0x00007f0bab929f2c (libKF6GuiAddons.so.6 + 0x40f2c) #8 0x00007f0bab91f468 (libKF6GuiAddons.so.6 + 0x36468) … #17 0x00007f0bab923626 (libKF6GuiAddons.so.6 + 0x3a626) ← ClipboardThread::run


**Source code correlation (from kguiaddons waylandclipboard.cpp):**

Frame #7 (offset 0x40f2c) corresponds to DataControlSource::ext_data_control_source_v1_send:
```cpp
// waylandclipboard.cpp:346-371
void DataControlSource::ext_data_control_source_v1_send(const QString &mime_type, int32_t fd)
{
    // ...
    ba = m_mimeData->data(send_mime_type);  // ← Line 370, calls QMimeData::data()
    // ...
}
Frame #17 (offset 0x3a626) corresponds to ClipboardThread::run (Wayland event loop).

But you're correct.  the direction is:

Klipper -to-  reads FROM -to- our DataControlSource

NOT “portal reading clipboard”.

The sequence is:

lamco-rdp-server calls SetSelection (announces clipboard)
portal-kde creates PortalMimeData
KSystemClipboard wraps it in DataControlSource on Wayland thread
Klipper (monitoring clipboard) requests to READ from our source
Compositor calls ext_data_control_source_v1_send on Wayland thread
Tries to access PortalMimeData → CRASH
The Threading Issue
My analysis focused on PortalMimeData::retrieveData() accessing main-thread objects, but I need to clarify:

The crash happens in QMimeData::data() BEFORE retrieveData() is called.

This suggests the QMimeData object itself may be invalid/corrupted when accessed from the Wayland thread, not just the retrieveData() implementation.

Possible causes:

PortalMimeData moved to Wayland thread violates QObject threading
Race condition where PortalMimeData is deleted while callback pending
Qt internals not thread-safe when QMimeData moved across threads


I used AI tools (Claude) to help analyze the ~2000 lines of source code and correlate the stack trace, but the analysis is based on:

Actual source code from xdg-desktop-portal-kde v6.5.5
Actual source code from kguiaddons
Real crash coredumps from production testing
Reproducible crash (100% on every SetSelection call)
I’m happy to provide more details, run additional tests, or refine the analysis based on your feedback.

Reproducibility
The crash is 100% reproducible on KDE Plasma 6.5.5 with Klipper enabled (default).

Test application: https://github.com/gregcman/lamco-rdp-server (currently private, can make specific test case public if helpful)

Questions for You
Is the threading explanation incorrect? Should QMimeData be safe to move across threads?
Could this be a QMimeData lifecycle issue instead (object deleted while callback pending)?
Would you like me to build with debug symbols and provide more detailed backtrace?
Should I test with specific Qt/KDE debug flags enabled?
I want to make sure the fix addresses the actual root cause, not just symptoms.

Please let me know what you think as this, I believe, is the correct way to harmoniously interact with Klipper for everybody instead of trying to fight it.

Thanks,
Greg Lamberson
Lamco Development
greg@lamco.io
https://www.lamco.ai
Comment 6 Greg Lamberson 2026-02-03 17:16:03 UTC
Re: the mutex: I see m_selectionLock in WaylandClipboard::mimeData(), but                                            
  DataControlSource::ext_data_control_source_v1_send() (waylandclipboard.cpp:370) calls m_mimeData->data() without holding a lock.                                                                                                                      
                                                                                                                             
  The crash occurs in ext_data_control_source_v1_send on the Wayland thread. Should this code path be holding m_selectionLock before accessing m_mimeData?                                                                                              
                                                                                                                             
  I can build with debug symbols and provide detailed backtrace if that would help clarify the root cause.
Comment 7 David Edmundson 2026-02-03 17:24:49 UTC
>  I can build with debug symbols and provide detailed backtrace if that would help clarify the root cause.

No, I think it's clear from the original trace.
Comment 8 David Edmundson 2026-02-03 17:25:15 UTC
*** Bug 515433 has been marked as a duplicate of this bug. ***
Comment 9 Greg Lamberson 2026-02-03 18:33:03 UTC
Additional threading issue found during testing:                                                                           
                                                                                                                             
  Portal emits SelectionTransfer signal from wrong thread, preventing D-Bus signal delivery.                                 
                                                                                                                             
  Journal log shows:                                                                                                         
    QtDBus: cannot relay signals from parent DesktopPortal(0x564f27001aa0 "")                                                
    unless they are emitted in the object's thread QThread(0x564f23a4f1d0 "Qt mainThread").                                  
    Current thread is QThread(0x564f2592f270 "").                                                                            
                                                                                                                             
  This occurs when SetSelection is called and portal needs to request data from the application. The signal is emitted from a worker thread instead of the main thread, so D-Bus blocks it.                                                             
                                                                                                                             
  Result: SelectionWrite never receives the signal, portal times out after 1 second, clipboard operation fails.              
                                                                                                                             
  This appears related to the same threading architecture issue. Fixing the threading model for clipboard operations may resolve both issues.

LEt me know if you would like any further information.

Thanks,
Greg Lamberosn
Comment 10 Bug Janitor Service 2026-02-04 10:03:55 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/517
Comment 11 Bug Janitor Service 2026-02-04 10:53:35 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kguiaddons/-/merge_requests/207
Comment 12 David Redondo 2026-02-04 13:28:35 UTC
Git commit 2c0d063e5773b9c30afe3d96b9c2f910cf3bcbc3 by David Redondo.
Committed on 04/02/2026 at 10:00.
Pushed by davidre into branch 'master'.

clipboard: Run data fetching in the correct thread

KSystemClipboard changed so it now runs in a separate thread. Because
we override retrieveData of our QMimeData this runs in this new thread
now. As a short term fix make it run in the correct thread again.
Longer term we should port it to use data control directly without the
intermediate layer of KSystemClipboard.

M  +3    -1    src/clipboard.cpp

https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/commit/2c0d063e5773b9c30afe3d96b9c2f910cf3bcbc3
Comment 13 Bug Janitor Service 2026-02-04 13:42:03 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/518
Comment 14 David Redondo 2026-02-04 13:52:29 UTC
Git commit 475741c26cbed5c40ddd6257400b9ed493495235 by David Redondo.
Committed on 04/02/2026 at 13:41.
Pushed by davidre into branch 'Plasma/6.6'.

clipboard: Run data fetching in the correct thread

KSystemClipboard changed so it now runs in a separate thread. Because
we override retrieveData of our QMimeData this runs in this new thread
now. As a short term fix make it run in the correct thread again.
Longer term we should port it to use data control directly without the
intermediate layer of KSystemClipboard.


(cherry picked from commit 2c0d063e5773b9c30afe3d96b9c2f910cf3bcbc3)

Co-authored-by: David Redondo <kde@david-redondo.de>

M  +3    -1    src/clipboard.cpp

https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/commit/475741c26cbed5c40ddd6257400b9ed493495235