Repository navigation
fix(clipboard): skip X11 control targets and bound each MIME read - #36
Merged
Nadim147c merged 2 commits intoOct 29, 2026
Merged
Conversation
- add a controlTargets blacklist: SAVE_TARGETS, TARGETS, TIMESTAMP, MULTIPLE, DELETE, INSERT_SELECTION, INSERT_PROPERTY, LENGTH - filter them in parse() next to isBadMime(), before retrieveData opens the pipe - GTK advertises SAVE_TARGETS but never writes to the fd nor closes it, which blocked the pipe read forever and stalled the whole watcher until the next selection change - uppercase X11 data targets (STRING, UTF8_STRING, TEXT, COMPOUND_TEXT) are intentionally kept: they carry real text
- read each MIME type with an idle timeout instead of an unbounded io.ReadAll: the deadline is reset before every read, so a payload that keeps streaming is never cut off - skip a MIME type that fails to read and keep the rest of the event, instead of discarding the whole clipboard event - wrap deadline errors with the elapsed timeout and bytes read, so the log reads "idle timeout after 1s with 0 bytes read" instead of a bare "i/o timeout" - add TestReadWithIdleTimeout: slow-but-continuous source, silent source, partial read
Owner
|
Sorry I don't know why but I did not get any notification for this PR. |
Owner
|
Thanks for the PR! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
retrieveDatareads every MIME type the offer advertises, sequentially, bycalling
receiveand then reading the pipe to EOF. Two things go wrong withthat:
1. Some advertised "MIME types" are not content. GTK advertises X11 ICCCM
control targets such as
SAVE_TARGETS(the clipboard-manager save handshake),TARGETSandTIMESTAMP. ForSAVE_TARGETSthe source never writes to the fdand never closes it, so
io.ReadAllblocks forever. Because the whole parseruns inside the Wayland event callback, the watcher stops dispatching until the
source is destroyed — which only happens on the next selection change.
Symptom:
wl-pasteand Ctrl+V show the new clipboard content immediately, butthe entry only appears in
yankd listafter you copy something else. On theunfixed build nothing is logged: the read is simply stuck.
2. One unreadable MIME type dropped the whole event.
parsereturned theerror on the first failing MIME type, discarding the event even though every
other MIME type had been read successfully.
Change
controlTargetsset —SAVE_TARGETS,TARGETS,TIMESTAMP,MULTIPLE,DELETE,INSERT_SELECTION,INSERT_PROPERTY,LENGTH— andskip those next to the existing
isBadMimefilter, before the pipe is opened.STRING,UTF8_STRING,TEXT,COMPOUND_TEXT) are deliberately not in the set: they are content ratherthan a handshake.
UTF8_STRINGis the text as UTF-8;STRING/TEXTare thesame text with non-ASCII escaped as
\uXXXX. Skipping every type whose namestarts with an uppercase letter — the shortcut another clipboard manager
(CopyQ) uses to dodge
SAVE_TARGETS— would silently drop that content, andyankd has no other path that recovers it.
mimeReadTimeout = 1s), with thedeadline reset before every read, so a payload that keeps streaming is never
cut off, while a target that goes silent is abandoned.
retrieveDataalready logs the error, so the read failure is still visiblein the daemon log.
Tests
TestReadWithIdleTimeoutcovers the new read loop:total run longer than it (so the timeout must be idle-based, not total)
returned with an error, so the caller discards it)
The "skip a failed MIME type" path needs a live offer object and has no unit
test; it was verified by running the daemon and copying from a browser.
Reproducing on the unfixed version
Whether this reproduces depends on the source: the extra target has to be
advertised, and only some clients do that. Firefox on Wayland does: it is a
GTK3/GDK application (it loads
libgtk-3/libgdk-3and runs withGDK_BACKEND=wayland), and the offers it makes carry the X11 ICCCMcompatibility names (
SAVE_TARGETS,TARGETS,TIMESTAMP) next toSTRING/TEXT/COMPOUND_TEXT.footandwl-copyimplementwl_data_sourcedirectly and never advertise those, which is why copying fromthem never hangs. Other GTK applications behave like Firefox.
When it is listed, on the unfixed build copying from Firefox produces no
daemon log line and no
yankd listentry until you copy something else; withthis change the entry lands immediately and the target is skipped before the
pipe is opened.
(The presence of
SAVE_TARGETSis not constant across copies — that is why thecheck above decides per offer instead of being assumed.)
After the change, an unknown target that never answers is abandoned after one
second and logged as