Don't hand WebKitGTK a paste of an empty clipboard #18

Closed
asxpi wants to merge 0 commits from asxpi/anotherim-js:fix/empty-paste into develop
First-time contributor

The bug. The desktop app on Linux (GTK 3 WebKitGTK, 2.54.1 in the GNOME 50 runtime) crashes with SIGSEGV on Ctrl+V or Shift+Insert when the clipboard is empty. On Wayland that means nothing has been copied since login, or the app that copied has quit. Reproduce with wl-copy --clear and then a paste in the chat. Symbolized:

#0 WebKit::Clipboard::formats(...)::$_0::operator() at Source/WebKit/UIProcess/gtk/ClipboardGtk3.cpp:85
     for (auto* atom : unsafeMakeSpan<GdkAtom>(atoms, atomsCount)) {
#2 request_targets_received_func at gtk/gtkclipboard.c:1332

GTK 3 reports a clipboard without targets as atoms == NULL, n_atoms == -1. A loop that ran zero times was turned into a span by WebKit's 308123@main, and the span takes -1 as its size. It's WebKit's bug: bugs.webkit.org 324466, with a fix in WebKit PR #77266. Until a fixed WebKitGTK reaches the Flatpak runtime, the app needs to work around it.

The change. no_empty_paste(window), next to no_pinch_zoom in page_window_made:

  • A thread-local flag tracks whether the clipboard is empty. It's refreshed with the same gtk_clipboard_request_targets WebKit uses, through a callback that handles -1, when the window is made and on the clipboard's owner-change (connected by name, since gtk-rs 0.18 doesn't bind it). Asking synchronously at the key would run a nested main loop in the handler.
  • The webview's key-press-event swallows Ctrl+V and Shift+Insert while the flag is set. Pasting nothing does nothing anyway.
  • Until the first answer the clipboard counts as non-empty, so a real paste is never dropped.

Once a fixed WebKitGTK ships it can go.

Checked in a local Flatpak build of 0.5.7 with this change, on GNOME 50 (Wayland): pasting an empty clipboard no longer crashes, and there was no core dump over a 15-minute session.

🤖 Generated with Claude Code

**The bug.** The desktop app on Linux (GTK 3 WebKitGTK, 2.54.1 in the GNOME 50 runtime) crashes with SIGSEGV on Ctrl+V or Shift+Insert when the clipboard is empty. On Wayland that means nothing has been copied since login, or the app that copied has quit. Reproduce with `wl-copy --clear` and then a paste in the chat. Symbolized: ``` #0 WebKit::Clipboard::formats(...)::$_0::operator() at Source/WebKit/UIProcess/gtk/ClipboardGtk3.cpp:85 for (auto* atom : unsafeMakeSpan<GdkAtom>(atoms, atomsCount)) { #2 request_targets_received_func at gtk/gtkclipboard.c:1332 ``` GTK 3 reports a clipboard without targets as `atoms == NULL`, `n_atoms == -1`. A loop that ran zero times was turned into a span by WebKit's 308123@main, and the span takes -1 as its size. It's WebKit's bug: [bugs.webkit.org 324466](https://bugs.webkit.org/show_bug.cgi?id=324466), with a fix in [WebKit PR #77266](https://github.com/WebKit/WebKit/pull/77266). Until a fixed WebKitGTK reaches the Flatpak runtime, the app needs to work around it. **The change.** `no_empty_paste(window)`, next to `no_pinch_zoom` in `page_window_made`: - A thread-local flag tracks whether the clipboard is empty. It's refreshed with the same `gtk_clipboard_request_targets` WebKit uses, through a callback that handles -1, when the window is made and on the clipboard's `owner-change` (connected by name, since gtk-rs 0.18 doesn't bind it). Asking synchronously at the key would run a nested main loop in the handler. - The webview's `key-press-event` swallows Ctrl+V and Shift+Insert while the flag is set. Pasting nothing does nothing anyway. - Until the first answer the clipboard counts as non-empty, so a real paste is never dropped. Once a fixed WebKitGTK ships it can go. **Checked** in a local Flatpak build of 0.5.7 with this change, on GNOME 50 (Wayland): pasting an empty clipboard no longer crashes, and there was no core dump over a 15-minute session. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Ctrl+V or Shift+Insert with an empty clipboard (no owner, e.g. after
`wl-copy --clear` on Wayland) crashes the desktop app with SIGSEGV in
WebKitGTK's Clipboard::formats(). GTK 3 reports the missing targets as
atoms == NULL, n_atoms == -1, and since 308123@main WebKit turns that
into a span of -1 entries. Present in WebKitGTK 2.54.1 (GNOME 50
runtime) and on WebKit main; reported as WebKit bug 324466, fix in
WebKit PR 77266.

Until a fixed WebKitGTK reaches the runtime, keep track of whether the
clipboard is empty, with the same targets request on window creation
and on owner-change, and swallow the paste keys on the webview while it
is. Until the first answer the clipboard counts as non-empty, so a real
paste is never dropped.

Assisted-by: Claude:opus-5-5
Owner

Merged into develop by hand as 899719b4 (2026-10-16), for 0.5.9. The approach is right and the review found one gap, fixed on top in bb88d923: the guard matched the paste by keyval, so on a layout whose V key gives another letter (Cyrillic em, say) Ctrl+V was not recognised while WebKit still took it as a paste by the key's Latin level, and the crash stayed for those users; the handler now also looks the hardware keycode up in the display's keymap and takes any group's v or V. Two notes, not changed: the PRIMARY-selection middle-click paste and WebKit's context-menu Paste are not covered, and between an owner-change and the targets answer the flag can be a few ms stale. Thank you.

Merged into develop by hand as 899719b4 (2026-10-16), for 0.5.9. The approach is right and the review found one gap, fixed on top in bb88d923: the guard matched the paste by keyval, so on a layout whose V key gives another letter (Cyrillic em, say) Ctrl+V was not recognised while WebKit still took it as a paste by the key's Latin level, and the crash stayed for those users; the handler now also looks the hardware keycode up in the display's keymap and takes any group's v or V. Two notes, not changed: the PRIMARY-selection middle-click paste and WebKit's context-menu Paste are not covered, and between an owner-change and the targets answer the flag can be a few ms stale. Thank you.
ann closed this pull request 2026-10-16 12:21:09 +00:00
ann referenced this pull request from a commit 2026-10-27 05:22:29 +00:00
Settings say less and show only what applies (the review of 2026-10-27, items 2-4, 7-12, 14-16 and 18, approved by the user, #18 "Agree. Replace.", which reverses the two-switch ruling of 2026-10-12): Appearance has one Theme choice, System, Day or Night, over the same state (followSystem/chooseTheme) in place of Follow the system and Night mode; Choose a picture and Forget the picture show only while Picture is the wallpaper or a refused picture has its reason to say; the apps say "on this device" where a browser tab says "in this browser" (the card's line, the wallpaper's, the picture's and its refusal); Render message styling is Format text (bold, italic, code), with no XEP number in its line; Room members beside the chat is gone (the panel's close and People button keep ROOM_MEMBERS) and Conversation details beside the chat is not offered in the Android app; Blocked contacts… moves from Privacy and security to each account's page, a card of its own that opens the list for that account; Log level, Log WebRTC internals, View log and the path show only while Write a log file is on, and a browser tab keeps the level; the app's and the account's Certificates cards show only while one is accepted, the browser's paragraph gone; Calls is one card, the devices with their tests, without the Android note; Sent files is the cap and one row "Clear sent-file copies (312 MB)…", its description one line; About draws the version and libtacky, the media engine only when it is unavailable, and the commit, the build date and where it runs (now in English only) go to Copy all; the account page's Advanced disclosure is WebSocket, and the Accounts, Appearance, Chats and About cards draw no heading that repeats the page's title (settings-rows card's `bare`, as the other settings worker has it). en.json and the six catalogues carry the new strings and lose the dead ones; CHANGELOG's Unreleased says it. Tests: preferences-views (the theme's one choice, the wallpaper's rows, the About lines and Copy all, the Android build in Copy all, the calls card, the categories' rows), preferences-cov, account-views (Blocked contacts on the account page, opened for it), account-fields-cov and certificates (no card while none is accepted, the app's listed), log-view (View log and the level only while the file is written), outbox (the size in the Clear row); the WebKit smoke's preferences screens follow, and new "settings safe" screens cover every page at 1440 and 360 px in Night and Day. make check STRICT=1 clean; make test-ui 359 files, 3882 passed, 8 skipped.
ann referenced this pull request from a commit 2026-10-27 13:09:52 +00:00
The remaining Lows of the final anotherim-js audit of 2026-10-27 (/data/another-im/audit-2026-10-27-final-anotherim-js.md): XEP-0439 actions are not drawn in rooms (#12: rowActions(m, room), message-row passes showNick, which both callers set from the chat's groupchat; libtacky refuses the press there and any occupant could draw buttons; whether action-selected goes out encrypted in an OMEMO chat is F2's libtacky half), a quick response chip shows the value it sends after its label whenever the two differ but for case and spacing (#13: XEP-0439 sends the value and only shows the label, so the new shownValue keeps the XEP and the reader sees the words before they go), isReportable is false for a room occupant's private chat since Blocking keeps bare JIDs and would block and report the whole room (#17, the safe one of the two choices), a vCard's tel: link carries data-ask and the link guard asks "Call {number}?" / "This opens {number} in your phone or calling app." before the opener in the shells and in a tab alike (#18), the desktop shell's openable hands a TEL: link on as tel: (#21, now a Cow), a gateway's auto-approved contact is added with no roster name instead of the subscribe nick (#19: their nick is their word, the name drawn then comes from their vCard or nick as theirs), and localHost, the page's sticker gate, also refuses a single-label host and names under .local, .localdomain, .home.arpa, .internal, .lan, .home, .intranet, .corp and .private, with the browser edition's remaining gap (a public-looking name resolving to a private address) documented at the function (#20). New strings in en, ru, uk, et and es; CHANGELOG Unreleased has a Security block naming the audit ids. Tests that failed before the fix (9 of them): quick-responses (rowActions in a room, shownValue, the chip showing "Large one Large"), report-spam (PM not reportable), requests (gateway contact added without a name), transfers (localHost local names), os-links (the tel question), links-cov (a data-ask tel opens through the question in a tab), vcard-profiles (tel link has data-ask); links.rs a_tel_scheme_in_upper_case_is_handed_on_in_lower_case. make -o audit check STRICT=1 clean (2110 keys), make test-ui 384 files 4246 passed 8 skipped, make test-shell ok, WebKit smoke 6769 ok with the contact info and profile card screens, its 4 FAILs the stale Android lock-line checks b1bdb10a fixed on develop.

Pull request closed

Sign in to join this conversation.
No description provided.