feat(cliprdr): add a clipboard sync loop detector - #1739
Open
Greg Lamberson (glamberson) wants to merge 1 commit into
Open
feat(cliprdr): add a clipboard sync loop detector#1739Greg Lamberson (glamberson) wants to merge 1 commit into
Greg Lamberson (glamberson) wants to merge 1 commit into
Conversation
An embedder bridging CLIPRDR to a local OS clipboard commonly hits a feedback loop: content copied on one side syncs to the other, the other side's own change notification fires for that same content, and the embedder syncs it back, forever. ironrdp-cliprdr has no visibility into the local OS clipboard on either side by design (that lives entirely in the embedder's CliprdrBackend implementation), so it can't detect this on its own, but nothing in the crate gives an embedder a building block to break the cycle either. Every consumer bridging to a real desktop clipboard ends up needing to write the same hash-and- time-window correlation logic themselves. Add LoopDetector: hashes recent format lists and content by source (Remote/Local) within a configurable time window, so an embedder can ask "would syncing this out right now just echo what the other side just sent" before acting, plus an optional per-source rate limit as a belt-and-suspenders guard against update storms. It takes an explicit now_ms on every call that needs the time rather than reading a clock itself, matching CliprdrBackend::now_ms()/elapsed_ms() already on this crate for the same wasm/test-determinism reasons. Hashing uses DefaultHasher rather than adding a crypto dependency: nothing here defends against an adversary, it only needs to avoid mistaking two different clipboard payloads for the same one within one process's own recent history. Tests live in ironrdp-testsuite-core since this crate sets [lib] test = false.
Greg Lamberson (glamberson)
temporarily deployed
to
llm-providers
August 21, 2026 03:04 — with
GitHub Actions
Inactive
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.
Summary
feedback loop: content copied on one side syncs to the other, the
other side's own change notification fires for that same content, and
the embedder syncs it back, forever. ironrdp-cliprdr has no visibility
into the local OS clipboard on either side by design (that lives
entirely in the embedder's CliprdrBackend implementation), so it
can't detect this on its own, but nothing in the crate gives an
embedder a building block to break the cycle either. Every consumer
bridging to a real desktop clipboard ends up needing to write the
same hash-and-time-window correlation logic themselves.
(Remote/Local) within a configurable time window, so an embedder can
ask "would syncing this out right now just echo what the other side
just sent" before acting, plus an optional per-source rate limit as
a belt-and-suspenders guard against update storms.
reading a clock itself, matching CliprdrBackend::now_ms()/elapsed_ms()
already on this crate for the same wasm/test-determinism reasons.
nothing here defends against an adversary, it only needs to avoid
mistaking two different clipboard payloads for the same one within
one process's own recent history.
siblings would_cause_content_loop/should_skip_sync. An earlier
version of this algorithm I'd written elsewhere hardcoded that
direction on would_cause_loop specifically, which was an
inconsistency with its own siblings rather than an intentional
asymmetry; fixed here.
Validation
cargo xtask check fmt/lints/tests/typos/locksall pass. Tests live inironrdp-testsuite-core since this crate sets [lib] test = false.
Notes
No public API break: this is a new module with entirely new public
types, no existing signature changes.